在 API 服务中访问 React 上下文

Access React context in an API service

在我的 React 应用程序中,我使用 context API 通过 useContext 挂钩存储用户信息:

const AuthContext = createContext<AuthContextType>(null!);

const useAuth = () => useContext(AuthContext);

function AuthProvider({ children }: { children: ReactNode }) {
    const [user, setUser] = useState<User>();

    // Implementations of values

    const value = useMemo(() => ({ user, login, logout }), [user]);

    return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

export { AuthProvider, useAuth };

访问授权信息在组件中一切正常,花花公子:

export default function CoolComponent() {
  const auth = useAuth();
  if (auth.user) {
    // Do something
  }
  return <div>Hello {auth.user}</div>;
}

问题是我的 jwt-token 存储在用户对象中,我的服务中的 API 调用需要它,但不允许在功能组件之外使用挂钩。我可以巧妙地规避这个问题吗?我能想到的一些事情是在每次调用服务时传递令牌(不是很干)或将令牌保存在 localStorage 中,然后在服务中从那里检索它,但似乎没有必要存储两个不同地方的相同信息?

更新:

现在服务代码:

const baseUrl = environment.apiUrl;

function getToken() {
  // This is what I would like to get some help with
}

const headers = {
  ...(getToken() && { Authorization: `Bearer ${getToken()}` }),
  "Content-Type": "application/json",
};

function getAllProjects(): Promise<IProject[]> {
  return fetch(`${baseUrl}projects`, {
    headers,
  }).then((response) => response.json());
}

function createProject(project: CreateProjectDTO): Promise<IProject> {
  return fetch(`${baseUrl}projects`, {
    method: "POST",
    headers,
    body: JSON.stringify(project),
  }).then((response) => response.json());
}

// + many more

export { getAllProjects, createProject };

在组件中调用服务:

useEffect(() => {
  const fetchProjects = async () => {
    setIsLoading(true);
    try {
      const allProjects = await getAllProjects();
      setProjects(allProjects);
    } catch (error) {
      // Handle error
    } finally {
      setIsLoading(false);
    }
  };
  fetchProjects();
}, []);

React documentation 说你不能在 JavaScript 函数中调用钩子。

你能做什么?

使用自定义挂钩。将函数重命名为 useCreateProject 和 return 您的函数。然后你就可以在你的自定义钩子中调用 useAuth:

 const useCreateProject =() =>{   
      const {user} = useAuth();
      
      function createProject(project: CreateProjectDTO): Promise<IProject> {
         return fetch(`${baseUrl}projects`, {
         method: "POST",
         headers,
         body: JSON.stringify(project),
        }).then((response) => response.json()); 
      }
 
      return createProject
 }

然后这样称呼它:

 const createProject = useCreateProject()
 useEffect(() => {
   const create = async () => {
     setIsLoading(true);
     try {
       await createProject()
     } catch (error) {
       // Handle error
     } finally {
       setIsLoading(false);
     }
   };
   create();
 }, []);

但我的建议是将令牌存储在 localStorage 或 cookie 中。当用户刷新页面时,上下文数据将丢失。但是,如果您不是这种情况,您可以继续使用上下文。