React hooks 的奇怪行为:延迟数据更新
Strange behavior of React hooks: delayed data update
奇怪的行为:我希望第一个和第二个 console.log 显示不同的结果,但它们显示相同的结果并且值仅在下次单击时更改。我应该如何编辑我的代码以使值不同?
function App() {
const [count, setCount] = React.useState(false);
const test = () => {
console.log(count); //false
setCount(!count);
console.log(count); //false
};
return (
<div className="App">
<h1 onClick={test}>Hello Whosebug</h1>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<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>
您可以在此处查看工作示例:
https://codesandbox.io/s/wz9y5lqyzk
State updates are asynchronous. The setCount
function you get from useState
无法神奇地伸出手来更改 count
常量的值。一方面,它是一个常数。另一方面,setCount
无权访问它。相反,当您调用 setCount
时,您的组件函数将被再次调用,并且 useState
将 return 更新后的计数。
实例:
const {useState} = React;
function Example() {
const [count, setCount] = useState(false);
const test = () =>{
setCount(!count); // Schedules asynchronous call to Example, re-rendering the component
};
return (
<div className="App">
<h1 onClick={test}>Hello CodeSandbox</h1>
<div>Count: {String(count)}</div>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
如果您需要在 count
更改时执行一些副作用,请使用 useEffect
:
useEffect(() => {
console.log(`count changed to ${count}`);
}, [count]);
请注意,我们告诉 useEffect
仅在 count
更改时调用我们的回调,因此如果我们有其他状态,我们的回调不会 运行 不必要地。
实例:
const {useState, useEffect} = React;
function Example() {
const [count, setCount] = useState(false);
const test = () =>{
setCount(!count); // Schedules asynchronous call to Example, re-rendering the component
};
useEffect(() => {
console.log(`count changed to ${count}`);
}, [count]);
return (
<div className="App">
<h1 onClick={test}>Hello CodeSandbox</h1>
<div>Count: {String(count)}</div>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
setState
挂钩不会直接更新组件中的值。它更新它的内部状态,导致组件重新渲染,然后 returns 新的状态值,您将其分配给 count
.
当您在 test
中 console.log(count)
时,您显示 count
的当前值,这是旧值(更新前)。如果将 console.log()
移至渲染,您将看到新值:
const { useState } = React;
const Component = () => {
const [count, setCount] = useState(false);
const test = () => {
console.log('before: ', count);
setCount(!count)
}
console.log('after: ', count);
return (
<div className="App">
<button onClick={test}>Click</button>
</div>
);
}
ReactDOM.render(
<Component />,
demo
);
<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="demo"></div>
状态更新是异步的,因此如果您使用 Hooks,您可以使用 useEffect
在更新后收到通知。
这是一个例子:
https://codesandbox.io/s/wxy342m6l
如果你正在使用 React 组件的 setState,你可以使用回调
this.setState((state) => ({count: !state.count}), () => console.log('Updated', this.state.count));
如果需要状态值,请记住使用回调来更新状态。
奇怪的行为:我希望第一个和第二个 console.log 显示不同的结果,但它们显示相同的结果并且值仅在下次单击时更改。我应该如何编辑我的代码以使值不同?
function App() {
const [count, setCount] = React.useState(false);
const test = () => {
console.log(count); //false
setCount(!count);
console.log(count); //false
};
return (
<div className="App">
<h1 onClick={test}>Hello Whosebug</h1>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<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>
您可以在此处查看工作示例: https://codesandbox.io/s/wz9y5lqyzk
State updates are asynchronous. The setCount
function you get from useState
无法神奇地伸出手来更改 count
常量的值。一方面,它是一个常数。另一方面,setCount
无权访问它。相反,当您调用 setCount
时,您的组件函数将被再次调用,并且 useState
将 return 更新后的计数。
实例:
const {useState} = React;
function Example() {
const [count, setCount] = useState(false);
const test = () =>{
setCount(!count); // Schedules asynchronous call to Example, re-rendering the component
};
return (
<div className="App">
<h1 onClick={test}>Hello CodeSandbox</h1>
<div>Count: {String(count)}</div>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
如果您需要在 count
更改时执行一些副作用,请使用 useEffect
:
useEffect(() => {
console.log(`count changed to ${count}`);
}, [count]);
请注意,我们告诉 useEffect
仅在 count
更改时调用我们的回调,因此如果我们有其他状态,我们的回调不会 运行 不必要地。
实例:
const {useState, useEffect} = React;
function Example() {
const [count, setCount] = useState(false);
const test = () =>{
setCount(!count); // Schedules asynchronous call to Example, re-rendering the component
};
useEffect(() => {
console.log(`count changed to ${count}`);
}, [count]);
return (
<div className="App">
<h1 onClick={test}>Hello CodeSandbox</h1>
<div>Count: {String(count)}</div>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
setState
挂钩不会直接更新组件中的值。它更新它的内部状态,导致组件重新渲染,然后 returns 新的状态值,您将其分配给 count
.
当您在 test
中 console.log(count)
时,您显示 count
的当前值,这是旧值(更新前)。如果将 console.log()
移至渲染,您将看到新值:
const { useState } = React;
const Component = () => {
const [count, setCount] = useState(false);
const test = () => {
console.log('before: ', count);
setCount(!count)
}
console.log('after: ', count);
return (
<div className="App">
<button onClick={test}>Click</button>
</div>
);
}
ReactDOM.render(
<Component />,
demo
);
<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="demo"></div>
状态更新是异步的,因此如果您使用 Hooks,您可以使用 useEffect
在更新后收到通知。
这是一个例子:
https://codesandbox.io/s/wxy342m6l
如果你正在使用 React 组件的 setState,你可以使用回调
this.setState((state) => ({count: !state.count}), () => console.log('Updated', this.state.count));
如果需要状态值,请记住使用回调来更新状态。