react中的异步函数不会对状态变化做出react

IT技术 javascript reactjs
2021-03-27 21:55:38

我希望我aysnc function对状态变化做出react,以便它可以在状态变化时终止。我发现它对改变状态没有react。

在提供的示例中,我从函数内部更改状态,但是我已经对其进行了测试并从函数外部(单击按钮)更改了状态,但它也不起作用

const [testVariable, setTestVariable] = useState(false);

useEffect(()=> {
  testFunction();
}, [])

const testFunction = async () => {
  await timeout(1000);

  console.log("Setting test variable to: " + true);
  setTestVariable(true);

  await timeout(1000);
  
  console.log("Test variable is: " + testVariable);
}

预期的结果是看到变量变为真,但是我看到的是: 在此处输入图片说明

4个回答

状态变量永远不会改变它们的值。(请注意,您可以,拥有并且应该声明它们,const因为它们不会改变)。

组件函数的后续调用将获得具有相同名称和不同值的新状态变量。

您的testFunction函数已关闭旧状态变量。


我怀疑你可以通过参考解决这个问题:

const [testVariable, setTestVariable] = useState(false);
const reference = useRef();
reference.current = testVariable;

… 然后让您的函数测试 的值reference.current而不是testVariable


然而,这确实感觉像是一个XY 问题,其中真正的解决方案是“使用您传递给的函数的返回值useEffect来停止您想要停止的任何内容”(并testVariable用作 的依赖项useEffect)。

你在使用 TypeScript 吗?
2021-06-07 21:55:38
这不是useRef- reactjs.org/docs/hooks-reference.html#useref的正确用例useRef应该用于将有状态变量从子组件传递到父组件。(例如:元素的详细视图具有对父列表中相同元素值的引用,以根据更改的属性更新父元素)。
2021-06-13 21:55:38
@KimBrunJørgensen — 请仔细阅读您刚刚分享的链接。它说“一个常见的用例是强制访问孩子”。普通并不意味着“只能接受”。它还说“但是,useRef() 不仅对 ref 属性有用。它对于保持任何可变值都很方便”。还要注意我的答案的最后一段,我建议可能存在更好的解决方案,但问题没有提供有关实际问题的足够信息。
2021-06-14 21:55:38
@昆汀是的。抱歉,我已经删除了我的评论。对于那些寻求 TypeScript 解决方案的人 - 你只需要使用useRef<VariableType>(), whereVariableType是你useState所持有的。例如boolean
2021-06-21 21:55:38

react 中的状态更新是异步的,这意味着您的状态将在下一个渲染周期中更改。您可以使用 Effect 钩子来跟踪任何状态是否发生变化。

useEffect(() => {
   console.log(testVariable);
}, [testVariable]);
在这种情况下,您应该将 的新值存储在testVariable内部的 const 中,async function并将其用作for循环的引用
2021-05-28 21:55:38
是的,我知道这一点,但我需要for在状态更改时终止异步函数内部
2021-06-18 21:55:38

将其更改为

const [testVariable, setTestVariable] = useState(false);

useEffect(()=> {
  testFunction();
}, [])

const testFunction = async () => {
  await timeout(1000);

  console.log("Setting test variable to: " + true);

  let newTestVariable = true;  
  setTestVariable(newTestVariable);

  await timeout(1000);
  
  console.log("Test variable is: " + newTestVariable);
}

更改状态变量是一个异步操作,并与称为事件循环的东西一起工作。当您执行 setTestVariable(true) 时,它不会立即更新。

async function 改变的状态,但你登录testVariable在相同的生命周期,这就是为什么它看起来好像状态没有改变。

如果您改为将代码更改为

const [testVariable, setTestVariable] = React.useState(false)

console.log('testVariable', testVariable)
React.useEffect(() => {
  testFunction()
}, [])

const testFunction = async () => {
  await timeout(1000)
  setTestVariable(!testVariable)
}

return <h2>{testVariable}</h2>

它将记录输出:

testVariable false
testVariable false
testVariable true
testVariable true

它显示两个日志两者的原因falsetrue是因为console.log是外部的React.useEffect(() => {}, [])(有状态react的组分这相当于componentDidMount)。React 首先console.log在组件挂载之前执行,然后在组件挂载之后执行里面的代码React.useEffect并重新渲染组件,从而console.log再次执行语句。

要仅登录一次,您必须将其更改React.useEffect为:

React.useEffect(() => {
  console.log('testVariable', testVariable)
  testFunction()
}, [testVariable])

向数组参数添加一个属性,将等效函数[testVariable]更改为的每个新状态上执行并为的函数 chat 执行React.useEffectcomponentDidMountcomponentDidMounttestVariable