Reactjs 在异步函数中使用React-useState钩子更新函数

Reactjs 在异步函数中使用React-useState钩子更新函数,reactjs,react-hooks,Reactjs,React Hooks,尝试设置状态似乎不会立即更新状态,我不确定如何达到预期的结果 const Settings = (props: Props) => { const { user } = props; const initState: State = { newName: user.displayName, newAvatarUrl: user.avatarUrl, disabled: false, }; c

尝试设置状态似乎不会立即更新状态,我不确定如何达到预期的结果

  const Settings = (props: Props) => {
      const { user } = props;
      const initState: State = {
        newName: user.displayName,
        newAvatarUrl: user.avatarUrl,
        disabled: false,
      };
      const [form, setForm] = useState(initState);

  const handleUploadFile = async () => {
    const fileElement = document.getElementById('upload-file') as HTMLFormElement;
    const file = fileElement.files[0];

    if (file == null) {
      return;
    }
    setForm({ ...form, disabled: true });

    try {
      const response = await asynFunc1()

      await asyncFun2(response)

      setForm({ ...form, newAvatarUrl: response.url });

      await asyncFunc3(form.newAvatarUrl) // Expected: response.url Observed: old value
    } catch (error) {
      consol.log(error)
    } finally {
      setForm({ ...form, disabled: false });
    }
  };

  return (
        <h4>Your Avatar</h4>
        <Avatar
          src={form.newAvatarUrl}
          style={{
            display: 'inline-flex',
            verticalAlign: 'middle',
            marginRight: 20,
            width: 60,
            height: 60,
          }}
        />
        <label htmlFor="upload-file">
          <Button variant="outlined" color="primary" component="span" disabled={form.disabled}>
            Update Avatar
          </Button>
        </label>
        <input
          accept="image/*"
          name="upload-file"
          id="upload-file"
          type="file"
          style={{ display: 'none' }}
          onChange={handleUploadFile}
        />
  );
};
const设置=(道具:道具)=>{
const{user}=props;
常量initState:状态={
newName:user.displayName,
newAvatarUrl:user.avatarUrl,
残疾人士:错,,
};
const[form,setForm]=useState(initState);
const handleUploadFile=async()=>{
const fileElement=document.getElementById('upload-file'),作为HTMLFormElement;
const file=fileElement.files[0];
if(file==null){
返回;
}
setForm({…form,disabled:true});
试一试{
const response=wait asynFunc1()
等待asyncFun2(响应)
setForm({…form,newAvatarUrl:response.url});
wait asyncFunc3(form.newAvatarUrl)//预期:response.url观察到:旧值
}捕获(错误){
控制台日志(错误)
}最后{
setForm({…form,disabled:false});
}
};
返回(
你的化身
更新头像
);
};

看起来setForm不是同步的,但它不返回承诺,因此我不确定如何以同步方式使用它。

如注释中所述,状态更新是异步的。相反,您应该将response.url传递给asyncFunc3调用,并在成功返回后设置表单状态。大概是这样的:

const设置=(道具:道具)=>{
const{user}=props;
常量initState:状态={
newName:user.displayName,
newAvatarUrl:user.avatarUrl,
残疾人士:错,,
};
const[form,setForm]=useState(initState);
const handleUploadFile=async()=>{
const fileElement=document.getElementById('upload-file'),作为HTMLFormElement;
const file=fileElement.files[0];
if(file==null){
返回;
}
setForm({…form,disabled:true});
试一试{
const response=wait asynFunc1()
等待asyncFun2(响应)
等待asyncFunc3(response.url)
setForm({…form,newAvatarUrl:response.url});
}捕获(错误){
控制台日志(错误)
}最后{
setForm({…form,disabled:false});
}
};
返回(
你的化身
更新头像
);
};

状态以异步方式更新。调用函数更新状态后,无法立即记录更新状态。组件必须重新渲染才能看到更新的状态。更新状态后,您可以使用
useffect
hook执行任何代码。@Yousaf谢谢。我更改了函数调用以使用所需的值,而不依赖于状态。视图仍然没有反映更新的状态,这意味着状态实际上没有更新,对吗?谢谢,这确实是我必须做的,以使逻辑正确。视图仍不反映更新的状态。我的印象是,更改状态会触发重新渲染,但我不确定如何以编程方式触发。可能是用户道具也正在更新,而整个内容都会重新渲染?如果没有更多的信息,我真的说不出来。也许你可以举一个关于感谢维克多的小例子。在键入一个示例时,我意识到是最后一个块过度编写了更新。你知道我怎样才能改变状态,就像最终的工作方式一样吗?是的,当你按照你在那里做的方式来解构状态对象时,你就是在解构你的初始状态(因此在某种竞争条件下过度写入)。请改为尝试执行此操作。
setState(prevState=>({…prevState,flag:false});
通过传递函数,您将获得状态“frame”,并且不会使用过时的状态对象。谢谢Viktor。