了解React hooks useEffect函数。useffect中的回调函数(即取消订阅)何时被调用?

Dee*_*ohn 5 reactjs react-hooks

我一直在尝试了解取消订阅(useEffect 中的回调)何时被准确调用。

这是codepen链接:https ://codepen.io/deen_john/pen/eYmNdMy 代码:

const { useState, useEffect } = React  ;
 
function App() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
    console.log("use effect called ");
    
    return () => {
      console.log("unsubscribe ")
    }
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'))
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>
Run Code Online (Sandbox Code Playgroud)

问题: 在我的示例中,每次我单击按钮(即每次更新按钮状态)时,useEffect 挂钩(即取消订阅)中的回调函数都会被调用。但是,根据 React 文档, useEffect 中的回调的工作方式类似于 componentWillUnmount 生命周期,因此在我的示例中,只有在卸载 App 组件时才应该调用它。我只是在这里更新按钮状态,而不是在每次点击时卸载应用程序组件。

Shu*_*tri 5

每次调用 useEffect 之前以及组件卸载时都会调用 useEffect 的取消订阅事件

由于在您的情况下,您尚未将任何依赖项数组传递给 useEffect,因此您的 useEffect 将在组件的每个渲染上运行,因此取消订阅将在触发下一个 useEffect 之前在每次重新渲染上运行

编写上述代码的更好方法是将依赖项数组中的 count 传递给 useEffect

const { useState, useEffect } = React;
 
function App() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
    console.log("use effect called ");
    
    return () => {
      console.log("unsubscribe ")
    }
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'))
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>
Run Code Online (Sandbox Code Playgroud)


cbd*_*per 2

React 将始终尝试保持您的效果更新。因此,每当它们运行时,默认情况下它都会尝试清除最后一个效果以应用新效果。

  • 每次渲染后运行的效果

因此,如果您的效果在每次渲染后运行,React 将在每次渲染后进行清理,然后应用新效果。

  • 基于某些依赖项运行的效果

如果你的效果依赖于一些变量(包含在依赖数组中[a,b, etc]来决定它是否应该再次运行,同样的情况也会发生。如果它再次运行,React将在运行效果之前运行清理函数。

  • 仅在第一次渲染后运行的效果

如果你的效果仅在第一次渲染后运行(具有空的依赖数组[]),那么 React 只会在组件卸载后进行清理。

例子:

下面的代码片段展示了这种行为。

function App() {
  console.log('Rendering App...');
  const [show2,setShow2] = React.useState(true);
  const [stateBool,setStateBool] = React.useState(true);
  return(
    <React.Fragment>
      <button onClick={()=>{
        console.clear();
        setStateBool((prevState)=>!prevState)}
      }>
        Update App
      </button>
      <button onClick={()=>{
        console.clear()
        setShow2((prevState)=>!prevState)}
      }>
        Toggle Component2
      </button>
      <Component1/>
      {show2 && <Component2/>}
    </React.Fragment>
  );
}

function Component1() {
  console.log('Rendering Component1...');
  React.useEffect(()=>{
    console.log('useEffect Component1 after every render...');
    return () => console.log('Cleaning up useEffect Component1...');
  });
  return(
    <div>Component1</div>
  );
}

function Component2() {
  console.log('Rendering Component2...');
  React.useEffect(()=>{
    console.log('useEffect Component2 only after 1st render...');
    return () => console.log('Cleaning up useEffect Component2...');
  },[]);
  return(
    <div>Component2</div>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
Run Code Online (Sandbox Code Playgroud)