我在React中使用useState钩子,它的行为很奇怪。

如果您看下面的示例,这是我所期望的:调用login,成功后调用setRefreshToken(responseToken),然后调用refresh(),该引用引用refreshToken中设置的setRefreshToken。实际上发生的是refreshTokenrefresh()内部未定义。

我知道setState是异步的,但我之前从未遇到过这样的问题。我想念什么吗?

import React, { createContext, useState } from "react";
import jwtDecode from "jwt-decode";

const localStorageKey = "ar_refresh_token";

export const AuthContext = createContext();

export function AuthProvider({ tokenUrl, registerUrl, refreshUrl, children }) {
  const [refreshToken, setRefreshToken] = useState(
    window.localStorage.getItem(localStorageKey)
  );

  const [accessToken, setAccessToken] = useState();

  const login = async (userId, password) => {
    const response = await fetch(tokenUrl, {
      method: "POST",
      mode: "cors",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        userId,
        password
      })
    });


    if (response.status === 201) {
      const token = await response.text();
      setRefreshToken(token);
      window.localStorage.setItem(localStorageKey, token);

      await refresh();
    }
  };

  const refresh = async () => {
    const response = await fetch(refreshUrl, {
      method: "POST",
      mode: "cors",
      headers: {
        "Content-Type": "application/json",
        Authorization: `JWT ${refreshToken}`
      }
    });


    if (response.status === 201) {
      const token = await response.text();
      setAccessToken(token);
    }
  };

  return (
    <AuthContext.Provider
      value={{
        refreshToken,
        accessToken,
        login,
        refresh
      }}
    >
      {children}
    </AuthContext.Provider>
  );
}


完整示例:https://github.com/analyticsrequired/auth-admin/blob/master/src/AuthContext.js

最佳答案

没错,在调用refresh之前不会重新渲染该组件,因此refreshToken中的refresh将是默认组件。

您可以改为将tokenlogin传递为refresh的参数,并使用它,它将按预期工作。

const login = async (userId, password) => {
  // ...
  if (response.status === 201) {
    // ...
    await refresh(token);
  }
};

const refresh = async refreshToken => {
  const response = await fetch(refreshUrl, {
    method: "POST",
    mode: "cors",
    headers: {
      "Content-Type": "application/json",
      Authorization: `JWT ${refreshToken}`
    }
  });

  // ...
};

09-18 12:04