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 组件时才应该调用它。我只是在这里更新按钮状态,而不是在每次点击时卸载应用程序组件。
每次调用 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)
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)
| 归档时间: |
|
| 查看次数: |
14186 次 |
| 最近记录: |