如何从React自定义Hook获取值?代码报错问题排查
你的代码存在这些核心问题:
违反React Hook的使用规则:
React Hook(包括你自定义的usePersistedState)只能在React组件的顶层或者其他自定义Hook的顶层调用,绝对不能在普通函数(比如你的getAll)里间接调用。你把GetToken当成普通函数来调用的方式,完全不符合Hook的使用规范,这是代码执行失败的核心原因。GetToken函数的参数传递逻辑错误:
你的usePersistedState第一个参数是存储的key,第二个是默认值,但GetToken把接收的参数直接传给了usePersistedState的第一个参数,同时还硬编码了第二个参数为'test',这和你要获取认证token的需求完全不匹配。服务层函数不应依赖React Hook:
getAll是纯服务层的请求函数,它的职责是发送HTTP请求,不应该和React的状态管理Hook耦合,正确的做法是通过参数接收需要的token,而不是自己去调用Hook获取。
正确的解决方法
方法1:直接从localStorage读取(最简单直接)
因为你的usePersistedState本质是把值存在localStorage里,所以在服务函数里可以直接读取存储的值,不需要通过Hook:
function getAll(pageNo, limit){ // 直接从localStorage获取存储的认证token const token = localStorage.getItem('authentication'); return httpClient({ url: `api/posts?page=${pageNo}&limit=${limit}`, method: 'GET', headers: { 'Content-type': 'application/json', 'Authorization': token ? `Bearer ${token}` : '', 'Access-Control-Allow-Origin': '*' }, }); }
方法2:在组件中获取token,传递给服务函数
如果你想保持服务函数的纯净性,不在里面直接操作localStorage,可以在使用getAll的React组件中通过usePersistedState获取token,再作为参数传给服务函数:
// React组件中的用法 function PostsComponent() { // 用自定义Hook获取存储的token const [token] = usePersistedState('authentication', ''); const fetchPosts = async () => { // 将token作为参数传给getAll const data = await getAll(1, 10, token); // 处理返回的数据 }; return <button onClick={fetchPosts}>获取帖子列表</button>; } // 修改getAll函数,新增token参数 function getAll(pageNo, limit, token){ return httpClient({ url: `api/posts?page=${pageNo}&limit=${limit}`, method: 'GET', headers: { 'Content-type': 'application/json', 'Authorization': token ? `Bearer ${token}` : '', 'Access-Control-Allow-Origin': '*' }, }); }
这种方式更符合分层思想,服务层只负责请求逻辑,状态获取交给React组件处理。
方法3:封装专属的token获取Hook(多组件复用场景)
如果需要在多个组件中获取认证token,可以封装一个专门的Hook来统一逻辑:
// 封装获取认证token的自定义Hook function useAuthToken() { // 固定使用'authentication'这个key const [token] = usePersistedState('authentication', ''); return token; } // 在组件中使用 function PostsComponent() { const token = useAuthToken(); const fetchPosts = async () => { const data = await getAll(1, 10, token); // 处理数据 }; return <button onClick={fetchPosts}>获取帖子</button>; }
这样后续如果需要修改token的存储key或者默认值,只需要修改useAuthToken这一处即可。
内容的提问来源于stack exchange,提问作者Subodh Joshi

