Redux状态更新缓慢求助:登录需多次点击才返回数据
问题:登录需点击三次才能获取数据,Reducer异步处理错误分析
我在调用API后的Reducer中编写了filter函数,未使用async完成,API调用环节应无问题。已尝试重置并返回状态,但状态无法立即更新为initialState,登录时需点击三次才能拿到返回数据。控制台日志显示问题出在Reducer中,相关代码及日志如下:
Reducer代码
const initialState = { users: [], newUsers: [] } export const Users = (state = initialState, action) => { let { user, email, password } = action switch (action.type) { case types.CREATE_USER: // call API - POST axiosUser.post('users', user) return state; case types.LOGIN_USER: // call api - GET USERS const res = axiosUser.get('users') res.then((res) => { const dataUsers = res.data const checkUser = dataUsers.filter(item => item.email === email && item.password === password) state.newUsers = checkUser }) console.log(state); return state; default: return state; } }
Login组件代码
const Login = () => { const newState = useSelector(state => state.Users.newUsers) const dispatch = useDispatch() const navigate = useNavigate() const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [submit, setSubmit] = useState(false) const handleSignIn = () => { if (email !== '' && password !== '') { dispatch(act_loginUser(email, password)) console.log(newState); /* newState.find(function (item) { if (item.email === email && item.password === password) { navigate('/account') } return 1 }) */ } else { setSubmit(true) } }
控制台日志
UsersReducer.js:25 {users: Array(0), newUsers: Array(0)} newUsers: Array(1)0: {firstName: 'Phạm', lastName: 'Bình', email: 'phamgiabinh95@gmail.com', password: '98700', id: 1} length: 1 [[Prototype]]: Array(0) users: [] [[Prototype]]: Object Login.js:17 [] length: 0 [[Prototype]]: Array(0) UsersReducer.js:25 {users: Array(0), newUsers: Array(1)} Login.js:17 [] UsersReducer.js:25 {users: Array(0), newUsers: Array(1)} Login.js:17 [{…}] 0: {firstName: 'Phạm', lastName: 'Bình', email: 'admin@gmail.com', password: '98700', id: 1} length: 1 [[Prototype]]: Array(0)
问题根源
- Reducer中直接修改原state:Reducer必须是纯函数,不能通过
state.newUsers = checkUser直接修改原状态对象,Redux依赖状态的不可变性来检测更新,直接修改会导致状态变化无法被捕获。 - Reducer中执行异步操作:Reducer是同步执行的,不能在里面写axios的
then回调。异步请求属于副作用操作,必须放到action creator中通过中间件(比如redux-thunk)处理。 - dispatch后立即读取旧状态:Redux状态更新是异步的,
dispatch调用后组件的useSelector不会立刻拿到新值,此时打印的还是更新前的旧状态。
修复方案
1. 用redux-thunk处理异步Action
把API请求逻辑移到action creator中,拿到数据后再触发同步action更新状态:
// action.js export const act_loginUser = (email, password) => { return async (dispatch) => { try { const res = await axiosUser.get('users'); const checkUser = res.data.filter(item => item.email === email && item.password === password); dispatch({ type: types.LOGIN_USER_SUCCESS, payload: checkUser }); } catch (err) { console.error('登录请求失败:', err); } }; };
2. 修改Reducer为纯函数
严格返回新的状态对象,不修改原state:
const initialState = { users: [], newUsers: [] } export const Users = (state = initialState, action) => { switch (action.type) { case types.CREATE_USER: // 同样需要把POST请求移到action中 return state; case types.LOGIN_USER_SUCCESS: // 解构原状态并替换newUsers字段,返回新对象 return { ...state, newUsers: action.payload }; default: return state; } }
3. 组件中监听状态变化执行跳转
用useEffect监听newState的变化,状态更新后再执行页面跳转:
const Login = () => { const newState = useSelector(state => state.Users.newUsers) const dispatch = useDispatch() const navigate = useNavigate() const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [submit, setSubmit] = useState(false) const handleSignIn = () => { if (email !== '' && password !== '') { dispatch(act_loginUser(email, password)) setSubmit(false); } else { setSubmit(true) } } // 监听newState变化,有匹配用户则跳转 useEffect(() => { if (newState.length > 0) { navigate('/account'); } }, [newState, navigate]); // ... 组件渲染逻辑 }
内容的提问来源于stack exchange,提问作者Bình Phạm Hữu
相关产品推荐
相关产品推荐

