Skip to content

Hooks 使用中的注意事项

几点注意事项

useState 初始化值,只有第一次有效

直接看代码

js
import { useState } from 'react';

// 子组件
function Child({ userInfo }) {
  // render: 初始化 state
  // re-render: 只恢复初始化的 state 值,不会再重新设置新的值
  // 只能用 setName 修改
  const [name, setName] = useState(userInfo.name);

  return (
    <div>
      <p>child, props name:{userInfo.name}</p>
      <p>child, state name:{name}</p>
    </div>
  );
}

function UseStateTrap() {
  const [name, setName] = useState('lzw');
  const userInfo = { name };

  return (
    <div>
      <div>
        parent &nbsp;
        <button onClick={() => setName('张三')}>setName</button>
      </div>
      ds
      <Child userInfo={userInfo} />
    </div>
  );
}

export default UseStateTrap;

初始值

js
child, props name:lzw
child, state name:lzw

点击 setName 后结果

js
child, props name:张三
child, state name:lzw

useEffect 内部不能修改 state

直接看代码

js
import { useEffect, useState } from 'react';

function UseEffectChangeState() {
  const [count, setCount] = useState(0);

  // 模拟 DidMount
  useEffect(() => {
    console.log('useEffect...', count);

    // 定时任务
    const timer = setInterval(() => {
      console.log('setInterval...', count);
      setCount(count + 1);
    }, 1000);

    // 清除定时任务
    return () => clearInterval(timer);
  }, []); // 依赖是 []

  // 依赖是 [] 时: re-render 不会重新执行 effect 函数
  // 没有依赖:re-render 会重新执行 effect 函数

  return <div>count: {count}</div>;
}

export default UseEffectChangeState;

控制台输出

js
useEffect... 0
setInterval... 0

解决办法

js
import { useEffect, useState, useRef } from 'react';

function UseEffectChangeState() {
  const [count, setCount] = useState(0);

  // 模拟 DidMount
  let countRef = useRef(0); //解决办法
  useEffect(() => {
    console.log('useEffect...', count);

    // 定时任务
    const timer = setInterval(() => {
      // console.log('setInterval...', count)
      // setCount(count + 1)
      //解决办法-----
      console.log('setInterval...', countRef.current);
      setCount(++countRef.current);
      //解决办法-----
    }, 1000);

    // 清除定时任务
    return () => clearInterval(timer);
  }, []); // 依赖是 []

  // 依赖是 [] 时: re-render 不会重新执行 effect 函数
  // 没有依赖:re-render 会重新执行 effect 函数

  return <div>count: {count}</div>;
}

export default UseEffectChangeState;

useEffect 可能出现死循环

死循环代码

js
import { useState, useEffect } from 'react';
import axios from 'axios';

// axios 返送网络请求
function useAxios(url, config = {}) {
  const [loading, setLoading] = useState(false);
  const [data, setData] = useState();
  const [error, setError] = useState();

  useEffect(
    () => {
      // 利用 axios 发送网络请求
      setLoading(true);
      axios
        .get(url) // 发送一个 get 请求
        .then((res) => setData(res))
        .catch((err) => setError(err))
        .finally(() => setLoading(false));
    },
    [url], // 只能使用值类型:a,b,c 这种,然后拼接成 const config = {a,b,c}
    //[url,config] // 如果使用 config 对象,就回出现死循环
    // 根本原因是 React 使用 Object.is 判断 依赖 是否变化
    // Object.is(1,1)  // true
    // Object.is('a','a') // true
    // Object.is({},{}) // false
    // Object.is([],[]) // false
  );

  return [loading, data, error];
}

export default useAxios;

基于 MIT 许可发布