在Async函数内使用React useState挂钩更新函数

时间:2020-08-31 11:05:33

标签: reactjs react-hooks

尝试设置状态似乎无法立即更新状态,我不确定如何实现所需的结果。

  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}
        />
  );
};

setForm似乎不是同步的,但是它没有返回promise,所以我不确定如何以同步方式使用它。

1 个答案:

答案 0 :(得分:1)

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

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)

      await asyncFunc3(response.url)
      
      setForm({ ...form, newAvatarUrl: response.url });
    } 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}
        />
  );
};