认识React Hooks

简介


React Hook 是 React 16.8的新特性,让函数组件能彻底取代class组件,可以实现去除state、生命周期、this绑定等操作。

React Hook详解之useState与useEffect


useState

useState主要用于状态管理,简化原先的状态管理值设置以及监听操作,以及避开了this单独绑定的操作。
代码:

import React, {useState} from 'react';
function App() {
    const [count, setCount] = useState(0);
    return (
        <div className="App">
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>Click me</button>
        </div>
    )
}
export default App;

效果:


image.png
  1. 首先,我们需要引入useState这个方法;
  2. useState在使用的时候传入一个初始值,这个函数会返回一个数组,数组中有两个变量;
    • 数组的第一个值是一个变量,变量值就是传入的参数;
    • 数组的第二个值是一个方法,用于对初始值进行修改;
  3. 后面我们可以额直接使用这个变量和方法,不涉及到this,就只相当于函数内部的变量,在return的时候使用到这些变量。

多个useState

代码:

import React, {useState} from 'react';
function App() {
    const [count, setCount] = useState(0);
    const [age, setAge] = useState(10);
    return (
        <div className="App">
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>Click me</button>
            <p>Your age if {age}</p>
            <button onClick={() => setAge(age + 1)}>Add age</button>
        </div>
    )
}
export default App;

效果:


image.png

useEffect(只传一个回调函数)

我们通过useState可以实现在函数组件中取代原乡class组件的state,那么原先组件的生命周期该怎么办呢?这里,我们需要使用useEffect
代码:

import React, {useState, useEffect} from 'react';
function Counter() {
    const [count, setCount] = useState(0)
    const [age, setAge] = useState(20)
    // 相当于 componentDidMount 和 componentDidUpdate
    useEffect(() => {
        console.log(`You clicked ${count} times`)
    })// 监控所有的state
    return (
        <div className="App">
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>Add Count</button>
            <p>You are {age} years old!</p>
            <button onClick={() => setAge(age + 1)}>Add Age</button>
        </div>
    )
}
export default Counter;

效果:


image.png
  1. 我们先引入useEffect;
  2. useEffect相当于 componentDidMount 和 componentDidUpdate,也就是初始化以及更新的时候就会触发传进去的函数

useEffect(传入第二个参数)

useEffect返回值的箭头函数用于执行清除,第二个参数为不空的数组表示只监控该state的状态。
代码:

import React, {useState, useEffect} from 'react';
function Counter() {
    const [count, setCount] = useState(0)
    const [age, setAge] = useState(20)
    useEffect(() => {
        console.log('挂载和状态更新时执行')
        return () => {
            console.log('状态更新和卸载组件的时候执行')
        }
    }, [count]) // 只监控count状态
    return (
        <div className="App">
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>Add Count</button>
            <p>You are {age} years old!</p>
            <button onClick={() => setAge(age + 1)}>Add Age</button>
        </div>
    )
}
export default Counter;

效果:


image.png
  1. useEffect的第一个参数为一个箭头函数,这个箭头函数会在挂载和状态更新的时候执行;箭头函数可以再返回一个箭头函数,这个返回的箭头函数会在状态更新和卸载组件的时候更新;
  2. useEffect可以加第二个参数,为不空的数组,表示需要监控的状态;不是这个数组里面的不进行监控;

useEffect(第二个参数为空数组)

useEffect第二个参数为空数组,等价于componentDidMount
代码:

import React, {useState, useEffect} from 'react';
function Counter() {
    const [count, setCount] = useState(0)
    const [age, setAge] = useState(20)
    
    // 箭头函数返回箭头函数的简单写法
    useEffect(() => () => {
        console.log('卸载执行')
    }, [])
    
    useEffect(() => {
        console.log('首次时执行')
        return () => {
            console.log('仅卸载时执行')
        }
    }, []) // 都不监控,只在第一次挂载的时候执行一次
    return (
        <div className="App">
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>Add Count</button>
            <p>You are {age} years old!</p>
            <button onClick={() => setAge(age + 1)}>Add Age</button>
        </div>
    )
}
export default Counter;

效果:


image.png

使用React Hook的规则


  1. 只在最顶层使用 Hook
    • 不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层以及任何 return 之前调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确。
  2. 只在 React 函数中调用 Hook
    • 可以在 React 的函数组件中调用 Hook
    • 可以在自定义 Hook 中调用其他 Hook

手动实现一个简单的React Hook


代码:

import React, {useState, useEffect} from 'react';
import ReactDOM from 'react-dom'
let memoizedState = []; // hooks 存放在这个数组
let cursor = 0; // 当前 memoizedState 下标
function render() {
    cursor = 0;
    ReactDOM.render(
        <App />,
        document.getElementById('root')
    )
}
function useState(initialValue) {
    memoizedState[cursor] = memoizedState[cursor] || initialValue;
    const currentCursor = cursor;
    function setState(newState) {
        memoizedState[currentCursor] = newState;
        render()
    }
    return [memoizedState[cursor++], setState]; // 返回当前state,并把cursor加1
}
function useEffect(callback, depArray) {
    const hasNoDeps = !depArray;
    const deeps = memoizedState[cursor];
    const hasChangeDeps = deps
        ? !depArray.every((el, i) => el === deps[i])
        : true;
    if (hasNoDeps || hasChangedDeps) {
        callback();
        memoizedState[cuesor] = depArray;
    }
    cursor++;
}
function App() {
    console.log('render app')
    const [count, setCount] = useState(100);
    const [name, setName] = useState('hunger')
    useEffect(() => {
        console.log('update', count)
    }, [count])
    return (
        <div className="App">
            <p>You clicked {count} times</p>
            <button onClick={() => setCpunt(count + 1)}>Add count</button>
            <p>Your name is {name}</p>
            <button onClick={() => setName(name + '!')}>Set name</button>
        </div>
    )
}
export default App;
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容