Unterschiede: 1. Hooks sind präziser geschrieben als Klassen. 2. Der Geschäftscode von Hooks ist stärker aggregiert als von Klassen. 3. Die logische Wiederverwendung von Klassenkomponenten verwendet normalerweise Render-Requisiten und HOC, während React-Hooks benutzerdefinierte Hooks zur Wiederverwendung von Logik bereitstellen .
Die Betriebsumgebung dieses Tutorials: Windows 7-System, Reaktionsversion 17.0.1, Dell G3-Computer.
Was sind die Unterschiede zwischen React Hooks und Klassenkomponenten? Vergleichen wir Reaktions-Hooks und Klassenkomponenten und sprechen wir über ihre Unterschiede.
Funktionskomponenten können keinen eigenen Status haben. Vor Hooks waren Funktionskomponenten zustandslos und der Status der übergeordneten Komponente wurde über Requisiten abgerufen. Hooks stellen jedoch useState bereit, um den internen Status der Funktionskomponente aufrechtzuerhalten.
Der Lebenszyklus der Komponente kann in Funktionskomponenten nicht überwacht werden. useEffect fasst mehrere Lebenszyklusfunktionen zusammen.
Der Lebenszyklus von Klassenkomponenten ist komplizierter (die Änderungen sind von Version 15 zu Version 16 groß).
Die Logik von Klassenkomponenten ist schwer wiederzuverwenden (HOC, Render-Requisiten).
Wir nehmen den einfachsten Zähler als Beispiel:
Klassenkomponente
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> ) } }
hooks
function ExampleOfHooks() { const [count, setCount] = useState(0) const handleClick = () => { setCount(count + 1) } return ( <div> <p>you click { count }</p> <button onClick={handleClick}>点击</button> </div> ) }
Sie können sehen, dass der Code, der Hooks verwendet, prägnanter und klarer ist als der Klassenkomponentencode.
Bei der Verwendung von Klassenkomponenten kommt es häufig vor, dass eine Funktion in zwei Lebenszyklusfunktionen vorkommt. Auf diese Weise kann es vorkommen, dass Sie vergessen, sie separat zu schreiben. Zum Beispiel:
let timer = null componentDidMount() { timer = setInterval(() => { // ... }, 1000) } // ... componentWillUnmount() { if (timer) clearInterval(timer) }
Da das Hinzufügen von Timern und das Löschen von Timern zwei unterschiedliche Lebenszyklusfunktionen umfassen, können viele andere Geschäftscodes dazwischen liegen, sodass Sie möglicherweise vergessen, den Timer zu löschen, wenn der Timer zum Löschen nicht hinzugefügt wird Wenn die Komponente deinstalliert wird, kann die Funktion des Servers Probleme wie Speicherverluste und kontinuierliche Netzwerkanfragen verursachen.
Aber die Verwendung von Hooks kann den Code zentralisieren, für uns einfacher verwalten und nicht so leicht vergessen:
useEffect(() => { let timer = setInterval(() => { // ... }, 1000) return () => { if (timer) clearInterval(timer) } }, [//...])
Wiederverwendung von Klassenkomponenten-Render-Requisiten
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
hooks Einige gängige API-Anwendungen
Diese Syntax ist die ES6-Array-Struktur. Der erste Wert des Arrays ist der deklarierte Status und der zweite Jeder Wert ist eine Funktion der Zustandsänderung. const [value, setValue] = useState(0)
Jeder Frame hat einen unabhängigen Status
Wenn der Status oder die Requisiten der Komponente aktualisiert werden, wird die Funktionskomponente erneut zum Rendern aufgerufen. Jedes Rendering ist unabhängig und verfügt über seine eigenen unabhängigen Requisiten und Zustände, die sich nicht auf andere Renderings auswirken.Ich persönlich verstehe, dass der unabhängige Status jedes Frames mithilfe der Verschlussmethode implementiert wird.
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> </> ) }Nach dem Login kopieren
2. useEffect
useEffect(() => { //handler function... return () => { // clean side effect } }, [//dep...])
Zu beachtende Punkte
useEffect ist asynchron und wird ausgeführt, nachdem das Rendern der Komponente abgeschlossen ist
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不会变化。
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)。
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> </> ) }
通过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
,因为会增加组件的耦合性。
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视频教程】
Das obige ist der detaillierte Inhalt vonWas sind die Unterschiede zwischen React Hook und Class?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!