【问题标题】:How can I call a callback that depends on an updated state in react?如何调用依赖于更新状态的回调?
【发布时间】:2021-12-30 00:38:10
【问题描述】:
function useRequest() {

  const [accessToken, setAccessToken] = useState(42);
  const [refreshToken, setRefreshToken] = useState(7);
  
  const request = async (url) => {
    try {
      const res = await axios.get(url, { Headers: { Auth: accessToken } });
    } catch (error) {
      if (error.response.status === 401) {
        refresh(() => request(url));
      }
    }
  }
  
  const refresh = async (callback) => {
    const res = await axios.get("myserver.com", { params: { refreshToken }});
    setAccessToken(res.data.accessToken);
    callback()
  }
  
  return request;

}

所以我想调用这个 api 并在访问令牌过期时刷新它。问题是,当我在刷新函数中设置访问令牌状态时,回调是用旧状态调用的,因为 setState 是异步的。在其他情况下,我可以只使用 useEffect 但我不确定在这种情况下该怎么做。

【问题讨论】:

  • 为什么不能使用useEffect?
  • useEffect 会是什么样子?感觉就像我必须添加另一个 useState 来保存需要在访问令牌更新后调用的回调。但是接下来的问题是如何确保回调状态在访问令牌状态之前更新。 @Cole 使用 ref 的建议对我来说是可行的,但我很想看看 useEffect 是如何工作的。

标签: javascript reactjs react-hooks use-state


【解决方案1】:

我认为您想将 accessToken 存储在 ref 而不是 state 中。

官方反应文档:https://reactjs.org/docs/hooks-reference.html#useref

useState 是异步的,因为 React 假定状态与 UI 相关,因此状态更新与 React 渲染生命周期耦合。

更新ref 是同步的,对于不需要触发 UI 更新的持久化数据来说是一个不错的选择。

您的代码,但使用 useRef

function useRequest() {

  const accessTokenRef = useRef(42);
  const [refreshToken, setRefreshToken] = useState(7);
  
  const request = async (url) => {
    try {
      const res = await axios.get(url, { Headers: { Auth: accessTokenRef.current } });
    } catch (error) {
      if (error.response.status === 401) {
        refresh(() => request(url));
      }
    }
  }
  
  const refresh = async (callback) => {
    const res = await axios.get("myserver.com", { params: { refreshToken }});
    accessTokenRef.current = res.data.accessToken;
    callback()
  }
  
  return request;

}

【讨论】:

  • 你也可以考虑将accessToken 存储在一个引用中,因为它可能也不与渲染生命周期相关
  • 这很好用!没错,令牌与 UI 并不真正相关,它们只需要在渲染之间持续存在,所以 ref 正是我所需要的。谢谢@Cole!
【解决方案2】:

如果您出于某种原因不想使用useEffect,另一种选择是将您设置的状态传递给request 函数,以便它不依赖于外部变量。

const request = async (url, accessToken = 42) => {
    try {
        const res = await axios.get(url, { Headers: { Auth: accessToken } });
    } catch (error) {
        if (error.response.status === 401) {
            refresh((accessToken) => request(url, accessToken));
        }
    }
}

const refresh = async (callback) => {
    const res = await axios.get("myserver.com");
    const { accessToken } = res.data;
    setAccessToken(accessToken);
    callback(accessToken);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多