反応フックとクラスの違いは何ですか?
相違点: 1. フックはクラスよりも簡潔に記述されます; 2. フックのビジネス コードはクラスよりも集約されています; 3. クラス コンポーネントのロジックの再利用では通常、レンダリング プロパティと HOC が使用されますが、反応フックは使用を提供しますロジックを再利用するためのカスタム フック。
このチュートリアルの動作環境: Windows7 システム、react17.0.1 バージョン、Dell G3 コンピューター。
反応フックとクラスコンポーネントの違いは何ですか?反応フックとクラスコンポーネントを比較し、それらの違いについて話しましょう。
react-hooks によって解決される問題
関数コンポーネントは独自の状態を持つことができません。フックが登場する前は、関数コンポーネントはステートレスであり、親コンポーネントの状態は props を通じて取得されていましたが、フックでは関数コンポーネントの内部状態を維持するための useState が提供されます。
コンポーネントのライフサイクルは、関数コンポーネントでは監視できません。 useEffect は複数のライフサイクル関数を集約します。
クラス コンポーネントのライフ サイクルはより複雑です (バージョン 15 からバージョン 16 への変更は大きくなります)。
クラス コンポーネント ロジックは再利用が困難です (HOC、レンダリング プロップ)。
クラスと比較したフックの利点 (比較)
1. 記述方法がより簡潔になります
私たちは以下を使用します最も単純なカウンター 例:
クラスコンポーネント
class ExampleOfClass extends Component { constructor(props) { super(props) this.state = { count: 1 } } handleClick = () => { let { count } = this.state this.setState({ count: count+1 }) } render() { const { count } = this.state return ( <div> <p>you click { count }</p> <button onClick={this.handleClick}>点击</button> </div> ) } }
フック
function ExampleOfHooks() { const [count, setCount] = useState(0) const handleClick = () => { setCount(count + 1) } return ( <div> <p>you click { count }</p> <button onClick={handleClick}>点击</button> </div> ) }
フックを使用したコードは次のとおりであることがわかります。クラスコンポーネントコードと比較して、より簡潔で明確です。
2. ビジネス コードはより集約されています
クラス コンポーネントを使用する場合、関数が 2 つのライフ サイクル関数に含まれることがよくあります。これらを別々に記述すると、場合によっては問題が発生する可能性があります。問題は忘れてください。例:
let timer = null componentDidMount() { timer = setInterval(() => { // ... }, 1000) } // ... componentWillUnmount() { if (timer) clearInterval(timer) }
タイマーの追加とタイマーのクリアは 2 つの異なるライフサイクル関数に含まれるため、間に他の多くのビジネス コードが存在する可能性があるため、コンポーネントが次の場合にタイマーのクリアを忘れる可能性があります。クリアタイマー機能を追加しないと、メモリリークや継続的なネットワークリクエストなどの問題が発生する可能性があります。
しかし、フックを使用すると、コードがより集中化され、管理しやすくなり、忘れにくくなります:
useEffect(() => { let timer = setInterval(() => { // ... }, 1000) return () => { if (timer) clearInterval(timer) } }, [//...])
3. 便利なロジックの再利用
クラス コンポーネントのロジック再利用では、通常、レンダー プロパティと HOC が使用されます。 React フックは、ロジックを再利用するためのカスタム フックを提供します。
以下では、例としてページ上のマウス位置を取得するロジックの再利用を取り上げています。
クラス コンポーネントのレンダー プロパティ メソッドの再利用
import React, { Component } from 'react' class MousePosition extends Component { constructor(props) { super(props) this.state = { x: 0, y: 0 } } handleMouseMove = (e) => { const { clientX, clientY } = e this.setState({ x: clientX, y: clientY }) } componentDidMount() { document.addEventListener('mousemove', this.handleMouseMove) } componentWillUnmount() { document.removeEventListener('mousemove', this.handleMouseMove) } render() { const { children } = this.props const { x, y } = this.state return( <div> { children({x, y}) } </div> ) } } // 使用 class Index extends Component { constructor(props) { super(props) } render() { return ( <MousePosition> { ({x, y}) => { return ( <div> <p>x:{x}, y: {y}</p> </div> ) } } </MousePosition> ) } } export default Index
カスタム フック メソッドの再利用
import React, { useEffect, useState } from 'react' function usePosition() { const [x, setX] = useState(0) const [y, setY] = useState(0) const handleMouseMove = (e) => { const { clientX, clientY } = e setX(clientX) setY(clientY) } useEffect(() => { document.addEventListener('mousemove', handleMouseMove) return () => { document.removeEventListener('mousemove', handleMouseMove) } }) return [ {x, y} ] } // 使用 function Index() { const [position] = usePosition() return( <div> <p>x:{position.x},y:{position.y}</p> </div> ) } export default Index
フックを使用すると、ロジックの再利用がより便利になり、使用するとロジックがより明確になることが明らかです。
#フックの一般的な API の使用法
1、useState
#Syntaxconst [value, setValue] = useState(0)
この構文は ES6 配列構造です。配列の最初の値は宣言された状態で、2 番目の値は状態変化機能。
私の個人的な理解では、各フレームの独立した状態はクロージャー メソッドを使用して実現されます。
function Example() { const [val, setVal] = useState(0) const timeoutFn = () => { setTimeout(() => { // 取得的值是点击按钮的状态,不是最新的状态 console.log(val) }, 1000) } return ( <> <p>{val}</p> <button onClick={()=>setVal(val+1)}>+</button> <button onClick={timeoutFn}>alertNumber</button> </> ) }
コンポーネントのステータスまたはプロパティが更新されると、関数コンポーネントはレンダリングのために再呼び出されます。各レンダリングは独立しており、独自の独立したプロパティと状態を持ち、他のレンダリングには影響しません。
2. useEffectSyntax
useEffect(() => {
//handler function...
return () => {
// clean side effect
}
}, [//dep...])
- useEffect は非同期であり、コンポーネントがレンダリングされるまで実行されません
- useEffect のコールバック関数は、副作用をクリアするか、返さない処理関数のみを返すことができます。
- useEffect によって渡された依存関係が空の配列の場合、useEffect 内の関数は1 回実行
useMemo および useCallback は主に、コンポーネントの更新数を減らし、コンポーネントのパフォーマンスを最適化するために使用されます。
- useMemo はコールバック関数と依存関係を受け取り、コールバック関数は依存関係が変更された場合にのみ再実行されます。
- useCallback は、コールバック関数と依存関係を受け取り、コールバック関数の記憶されたバージョンを返します。記憶されたバージョンは、依存関係が変更された場合にのみ再記憶されます。
const memoDate = useMemo(() => data, [//dep...])
const memoCb = useCallback(() => {//...}, [//dep...])
比如下面这种场景,改变子组件的name值后由于父组件更新后每次都会生成新值(addAge函数会改变),所以子组件也会重新渲染。
function Parent() { const [name, setName] = useState('cc') const [age, setAge] = useState(22) const addAge = () => { setAge(age + 1) } return ( <> <p>父组件</p> <input value={name} onChange={(e) => setName(e.target.value)} /> <p>age: {age}</p> <p>-------------------------</p> <Child addAge={addAge} /> </> ) } const Child = memo((props) => { const { addAge } = props console.log('child component update') return ( <> <p>子组件</p> <button onClick={addAge}>click</button> </> ) })
使用useCallback优化
function Parent() { const [name, setName] = useState('cc') const [age, setAge] = useState(22) const addAge = useCallback(() => { setAge(age + 1) }, [age]) return ( <> <p>父组件</p> <input value={name} onChange={(e) => setName(e.target.value)} /> <p>age: {age}</p> <p>-------------------------</p> <Child addAge={addAge} /> </> ) } const Child = memo((props) => { const { addAge } = props console.log('child component update') return ( <> <p>子组件</p> <button onClick={addAge}>click</button> </> ) })
只有useCallback的依赖性发生变化时,才会重新生成memorize函数。所以当改变name的状态是addAge不会变化。
4、useRef
useRef类似于react.createRef。
const node = useRef(initRef)
useRef 返回一个可变的 ref 对象,其 current 属性被初始化为传入的参数(initRef)
作用在DOM上
const node = useRef(null) <input ref={node} />
这样可以通过node.current属性访问到该DOM元素。
需要注意的是useRef创建的对象在组件的整个生命周期内保持不变,也就是说每次重新渲染函数组件时,返回的ref 对象都是同一个(使用 React.createRef ,每次重新渲染组件都会重新创建 ref)。
5、useReducer
useReducer类似于redux中的reducer。
语法
const [state, dispatch] = useReducer(reducer, initstate)
useReducer传入一个计算函数和初始化state,类似于redux。通过返回的state我们可以访问状态,通过dispatch可以对状态作修改。
const initstate = 0; function reducer(state, action) { switch (action.type) { case 'increment': return {number: state.number + 1}; case 'decrement': return {number: state.number - 1}; default: throw new Error(); } } function Counter(){ const [state, dispatch] = useReducer(reducer, initstate); return ( <> Count: {state.number} <button onClick={() => dispatch({type: 'increment'})}>+</button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> </> ) }
6、useContext
通过useContext我们可以更加方便的获取上层组件提供的context。
父组件
import React, { createContext, Children } from 'react' import Child from './child' export const MyContext = createContext() export default function Parent() { return ( <div> <p>Parent</p> <MyContext.Provider value={{name: 'cc', age: 21}}> <Child /> </MyContext.Provider> </div> ) }
子组件
import React, { useContext } from 'react' import { MyContext } from './parent' export default function Parent() { const data = useContext(MyContext) // 获取父组件提供的context console.log(data) return ( <div> <p>Child</p> </div> ) }
使用步骤
- 父组件创建并导出
context:export const MyContext = createContext()
- 父组件使用
provider
和value
提供值:<MyContext.provide value={{name: 'cc', age: 22}} />
- 子组件导入父组件的
context:import { MyContext } from './parent'
- 获取父组件提供的值:
const data = useContext(MyContext)
不过在多数情况下我们都不建议使用context
,因为会增加组件的耦合性。
7、useLayoutEffect
useEffect 在全部渲染完毕后才会执行;useLayoutEffect 会在 浏览器 layout之后,painting之前执行,并且会柱塞DOM;可以使用它来读取 DOM 布局并同步触发重渲染。
export default function LayoutEffect() { const [color, setColor] = useState('red') useLayoutEffect(() => { alert(color) // 会阻塞DOM的渲染 }); useEffect(() => { alert(color) // 不会阻塞 }) return ( <> <div id="myDiv" style={{ background: color }}>颜色</div> <button onClick={() => setColor('red')}>红</button> <button onClick={() => setColor('yellow')}>黄</button> </> ) }
上面的例子中useLayoutEffect会在painting之前执行,useEffect在painting之后执行。
hooks让函数组件拥有了内部状态、生命周期,使用hooks让代码更加的简介,自定义hooks方便了对逻辑的复用,并且摆脱了class组件的this问题;但是在使用hooks时会产生一些闭包问题,需要仔细使用。
【相关推荐:Redis视频教程】
以上が反応フックとクラスの違いは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









クラスとメソッドの概念とインスタンス クラス (Class): 同じプロパティとメソッドを持つオブジェクトのコレクションを記述するために使用されます。コレクション内のすべてのオブジェクトに共通のプロパティとメソッドを定義します。オブジェクトはクラスのインスタンスです。メソッド: クラスで定義された関数。クラス構築メソッド __init__(): クラスには init() という名前の特別なメソッド (構築メソッド) があり、クラスがインスタンス化されるときに自動的に呼び出されます。インスタンス変数: クラスの宣言において、属性を変数で表現したものをインスタンス変数と呼びます。インスタンス変数とは、self で修飾された変数です。インスタンス化: クラスのインスタンス、クラスの特定のオブジェクトを作成します。継承: つまり、派生クラス (派生クラス) は基本クラス (ベースクラス) を継承します。

クラスとはPythonでクラスを定義するためのキーワードです クラスの定義方法:classの後ろにスペースを入れてからクラス名を追加します; クラス名のルール:最初の文字を大文字にします 複数の単語がある場合はキャメルケースを使用してください[class Dog()] などの名前付け。

jQuery は、Web 開発で広く使用されている古典的な JavaScript ライブラリで、イベントの処理、DOM 要素の操作、Web ページ上でのアニメーションの実行などの操作を簡素化します。 jQueryを使っていると要素のクラス名を置き換える場面がよくありますが、この記事ではその実践的な方法と具体的なコード例を紹介します。 1.removeClass() メソッドと addClass() メソッドを使用する jQuery には、削除用の RemoveClass() メソッドが用意されています。

PHP コードを記述するとき、クラスを使用するのは非常に一般的な方法です。クラスを使用すると、関連する関数とデータを 1 つのユニットにカプセル化できるため、コードがより明確になり、読みやすく、保守しやすくなります。この記事では、PHPClass の使用法を詳しく紹介し、クラスを適用して実際のプロジェクトでコードを最適化する方法を読者がよりよく理解できるように、具体的なコード例を示します。 1. クラスの作成と使用 PHP では、キーワード class を使用してクラスを定義し、クラス内のプロパティとメソッドを定義できます。

Vue エラー: v-bind を使用してクラスとスタイルを正しくバインドできません。解決方法は? Vue 開発では、v-bind 命令を使用してクラスとスタイルを動的にバインドすることがよくありますが、v-bind を正しく使用してクラスとスタイルをバインドできないなどの問題が発生することがあります。この記事では、この問題の原因と解決策を説明します。まず、v-bind ディレクティブを理解しましょう。 v-bind は V をバインドするために使用されます

背景 最近、jd-gui などの逆コンパイル ツールによってエンジニアリング コードが簡単に復元されないようにするために、企業のフレームワークでは主要なビジネス コードが暗号化されていますが、関連する難読化スキームの構成と使用は比較的複雑であり、多くの問題が発生しています。 springboot プロジェクトなので、クラス ファイルが暗号化されて渡されます。カスタム クラスローダが復号化されてロードされます。このソリューションは絶対に安全というわけではありません。逆コンパイルの難易度が上がるだけです。紳士は阻止できますが、悪党は阻止できません。全体的な暗号化保護のフローチャートが示されています。 Maven プラグインの暗号化では、カスタム Maven プラグインを使用してコンパイルします。指定されたクラス ファイルが暗号化され、暗号化されたクラス ファイルが指定されたパスにコピーされます。ここでは、resource/corecla に保存されます。

jquery が要素にクラスがあるかどうかを判断する方法: 1. 「hasClass('classname')」メソッドを通じて要素に特定のクラスがあるかどうかを判断します; 2. 「is('.classname」を通じて要素に特定のクラスがあるかどうかを判断します。 ')" 方法。
![「[Vue warn]: v-bind:class/ :class」エラーを解決する方法](https://img.php.cn/upload/article/000/465/014/169300902772563.jpg?x-oss-process=image/resize,m_fill,h_207,w_330)
「[Vuewarn]:v-bind:class/:class」エラーを解決する方法 Vue を使用した開発プロセス中に、いくつかのエラー プロンプトに遭遇することがよくあります。一般的なエラーの 1 つは、「[Vuewarn]:v-bind:class」です。 「/:クラス」エラー。このエラー メッセージは通常、v-bind:class または :class 属性を使用するときに表示され、Vue が設定したクラス値を正しく解析できないことを示します。そうすると、
