代码之家  ›  专栏  ›  技术社区  ›  Enrique Moreno Tent

反应钩子-即使状态没有改变,使用效果也会发射

  •  0
  • Enrique Moreno Tent  · 技术社区  · 6 年前

    我在我的组件中设置了一个效果,如果另一个状态属性发生变化,它会改变视图。但由于某些原因,当组件挂载时,即使 detailIndex 没有改变。

    const EventsSearchList = () => {
        const [view, setView] = useState('table');
        const [detailIndex, setDetailIndex] = useState(null);
    
        useEffect(() => {
            console.log('onMount', detailIndex);
            // On mount shows "null"
        }, []);
    
    
        useEffect(
            a => {
                console.log('Running effect', detailIndex);
                // On mount shows "null"!! Should not have run...
                setView('detail');
            },
            [detailIndex]
        );
    
        return <div>123</div>;
    
    };
    

    为什么会这样?

    :如果不清楚,我尝试的是在组件更新时运行效果,因为 变化。当它上升的时候就不会了。

    2 回复  |  直到 6 年前
        1
  •  9
  •   r g    6 年前

    useEffect 总是 在坐骑上执行。在你的情况下你的第二个 detailIndex 变化。

    更多信息: https://reactjs.org/docs/hooks-effect.html

        2
  •  4
  •   Baroudi Safwen    4 年前

    在我的例子中,尽管我在useEffect()中使用了第二个参数,而且我正在打印参数以确保它没有更改,也没有更改,但组件仍在不断更新。问题是,我用map()渲染组件,在某些情况下,键发生了变化,如果键发生了变化,那么react就是一个完全不同的对象。

        3
  •  1
  •   Dan Hunex    4 年前

    您可以添加第二个保护,检查detailIndex是否已从初始值更改为-1

     useEffect(
        a => {
         if(detailIndex != -1)
          {  console.log('Running effect', detailIndex);
            // On mount shows "null"!! Should not have run...
            setView('detail');
        }},
        [detailIndex]);
    
        4
  •  0
  •   Pavel Ye    5 年前

    useEffect 总是在初始渲染之后运行。

    docs :

    对!默认情况下,两者都运行 安装和更新,您可能会发现更容易想到 渲染后效果发生。React保证DOM

    关于您的代码,以下代码将只运行一次,因为没有指定依赖项( 使用效果 将可选的依赖项数组作为第二个参数):

    useEffect(() => {
      console.log('onMount', detailIndex);
      // On mount shows "null" -> since default value for detailIndex is null as seen above
      // const [detailIndex, setDetailIndex] = useState(null);
    }, []);
    

    detailIndex 更改(尝试呼叫 setDetailIndex 使用效果 ):

    useEffect(() =>
      // ... effect code
    }, [detailIndex]);
    

    useEffect hook API reference

        5
  •  0
  •   Emre Tapcı    4 年前

    useEffect 的第二个参数状态通过引用(而不是值)更改,效果将激发。

    import React, { useState, useEffect } from 'react';
        function App() {
            const [x, setX] = useState({ a: 1 });
            useEffect(() => {
                console.log('x');
            }, [x]);
            setInterval(() => setX({ a: 1 }), 1000);
            return <div></div>
        }
    }
    export default App;
    

    setX({a: 1}) 被称为, x 状态更新为对新对象的新引用。

    setX({a:1}) 被替换为 setX(1) ,效应不会周期性地发射。

        6
  •  0
  •   vsync    4 年前

    一种确保代码只在 “真实的” 同样在第一次渲染时,也要指定一个变量 false true 第一次渲染后 hook ,因此它将被记录在组件的整个生命周期中。

    const {useEffect, useRef, useState} = React
    
    const App = () => {
      const mountedRef = useRef()                 // ← the "flag"
      const [value, setValue] = useState(false)   // simulate a state change 
      
      // with the trick
      useEffect(() => {
          if (mountedRef.current){                // ← the trick
              console.log("trick: changed")
          }
      }, [value])
    
      // without the trick
      useEffect(() => {
         console.log("regular: changed")
      }, [value])
    
      // fires once & sets "mountedRef" ref to "true"
      useEffect(() => {
        console.log("rendered")
        mountedRef.current = true
        // update the state after some time
        setTimeout(setValue, 1000, true)
      }, [])
        
      return null
    }
    
    ReactDOM.render(<App/>, document.getElementById("root"))
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <div id="root"></div>