React useState setRes赋值不生效与前端鉴权问题排查
状态不更新的核心原因
你遇到的setRes赋值后不符合预期,本质是两个问题叠加导致的,不是React useState本身的bug:
- 封装的login函数返回值逻辑有缺陷
- 你混用了
async/await和.then()链式调用,还在.then()的回调函数前错误加了await关键字,干扰了Promise的正常返回流程。 - 你用了全局变量
result存返回结果,当接口返回auth === 'normal'的分支时,你只执行了页面跳转,没有给result赋值,函数会返回初始空对象;同时全局变量在多次并发请求时会出现值互相覆盖的问题,返回结果不可控。 - catch分支里给result赋值时没有加
type字段,返回结构和你预期的不一致,会导致条件渲染判断失效。
- 你混用了
- 对React状态更新机制存在误解
如果你是在setRes(respond)下一行立刻打印res查看值,拿到的一定是旧值——React的state更新是异步批量执行的,调用setRes后不会立刻修改当前作用域里的res变量,新值会在下一次组件渲染时生效,这不是更新失败。要确认更新结果,要么在JSX渲染部分直接输出res,要么用useEffect监听res变化后打印。
另外你在login函数里重复调用了e.preventDefault(),外层Handlelogin已经做过表单默认事件阻止,属于冗余代码,不会影响功能但没必要。
可直接用的修复代码
首先重构login请求函数,去掉全局变量,统一用async/await写法,保证所有分支都返回结构一致的对象:
import axios from "axios"; export const login = async (e) => { const data = { username: e.target[0].value, password: e.target[1].value } try { const response = await axios.post("http://localhost:3001/api/Login", data) const authType = response.data.auth switch(authType) { case false: return { auth: false, reason: "Wrong Credentials!", type: 'error' } case "Network Error": return { auth: false, reason: "Please check your network connection!", type: 'error' } case 'normal': window.location.href = response.data.to return { auth: true, type: 'normal' } case 'admin': case 'fs': return { auth: true, type: authType } default: return { auth: false, reason: "Unknown error", type: 'error' } } } catch (error) { return { auth: false, reason: "Network Error", type: 'error' } } }
组件部分调整如下,加状态监听方便确认更新结果:
const [res, setRes] = useState({ auth: false, type: '', reason: '' }) // 监听res变化,确认更新结果 useEffect(() => { console.log('最新登录状态:', res) }, [res]) const Handlelogin = async (e) => { e.preventDefault(); const respond = await login(e) setRes(respond) }
你写的条件渲染JSX本身没有语法问题,res值正确后就能正常匹配渲染对应组件。
现有鉴权实现的问题
这套逻辑本地测试没问题,但上线存在明显的安全和体验缺陷:
- 登录状态存在组件state中,页面刷新就会丢失,用户每次刷新都需要重新登录。建议登录成功后把后端返回的身份凭证(如Token)存在httpOnly Cookie或者localStorage中,页面初始化时优先读取本地存储校验登录状态,避免重复登录。
- 前端的条件渲染只能做展示层的跳转控制,所有管理员权限的接口必须在后端做二次权限校验,前端存储的auth、type字段用户可以手动修改,完全可以绕过前端判断直接请求敏感接口。
normal用户分支直接用后端返回的to字段做整页跳转,存在开放重定向风险,需要前后端都做跳转地址白名单校验,避免被利用跳转到钓鱼网站。- 不建议用
e.target[0].value这种索引方式取表单值,后续如果调整表单项顺序,很容易出现拿错账号密码的问题,建议给输入框加name属性,用FormData或者受控组件的方式获取表单值。
内容的提问来源于stack exchange,提问作者Firas SCMP
相关产品推荐
相关产品推荐

