V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
rabbbit
V2EX  ›  问与答

关于 React Hook 的问题, 如何避免子组件不必要的更新?

  •  
  •   rabbbit · 2022-05-20 20:50:53 +08:00 · 548 次点击
    这是一个创建于 697 天前的主题,其中的信息可能已经有所发展或是发生改变。

    代码大致逻辑如下, const b 基于 a 生成(实际上 a 是通过 props 传进来的),并传递给组件 Child.
    根据输出可以注意到子组件 Child 被调用了两次.
    怎么做才能避免 Child 不必要二次更新呢?

    function createB(a) {
      return { a };
    }
    
    export default function Index() {
      const [a, setA] = useState(0);
      const [b, setB] = useState(createB(a));
    
      useEffect(() => {
        console.log('b', b);
        setB(createB(a));
      }, [a]);
    
      return <Child b={b}></Child>;
    }
    
    function Child(props) {
      const b = props.b;
      useEffect(() => {
        console.log('child b', b);
      }, [b]);
      return <div>{b.a}</div>;
    }
    

    输出

    child b {a: 0}
    b {a: 0}
    child b {a: 0}
    
    第 1 条附言  ·  2022-05-20 21:27:07 +08:00
    呃, 解决了, 加个 useRef 跳过 componentDidMount 就行了.

    ```
    export default function Index() {
    const [a, setA] = useState(0);
    const [b, setB] = useState(createB(a));
    const first = useRef(true);
    useEffect(() => {
    if (first.current) {
    first.current = false;
    return;
    }
    console.log('b', b);
    setB(createB(a));
    }, [a]);

    return <Child b={b}></Child>;
    }


    ```
    第 2 条附言  ·  2022-05-20 21:29:26 +08:00
    b 是个很复杂的树形结构对象, 用 React.memo 判断是否相同很麻烦.
    第 3 条附言  ·  2022-05-20 21:48:31 +08:00
    useMemo 是个好办法, 直接一行就搞定了.

    ```
    export default function Index() {
    const [a, setA] = useState(0);
    const b = useMemo(() => createB(a), [a]);

    return <Child b={b}></Child>;
    }
    ```
    第 4 条附言  ·  2022-05-20 21:54:40 +08:00
    唉, 传入数据 a 生成 b. 然后组件内操作导致 b 更新后又要转成 a 传出去, 最后 a 又传进来转回 b.
    感觉像吃饱了撑的.
    aaronlam
        1
    aaronlam  
       2022-05-20 21:11:39 +08:00   ❤️ 1
    React.memo 一下 Child 组件
    rabbbit
        2
    rabbbit  
    OP
       2022-05-20 21:20:24 +08:00
    问题描述有点问题, 改一下应该是:

    怎样才能避免 Index 没必要的二次调用 createB(a) ?
    createB 返回的是个树形结构,开销还蛮大的.
    fayetitus
        3
    fayetitus  
       2022-05-20 21:21:59 +08:00 via Android   ❤️ 1
    @rabbbit 你需要 useMemo
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1712 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 16:43 · PVG 00:43 · LAX 09:43 · JFK 12:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.