【问题标题】:Redux won't update stateRedux 不会更新状态
【发布时间】:2021-09-12 03:02:23
【问题描述】:

我是第一次使用 Redux,我的演示应用不会更新其默认状态。我也尝试过使用 useEffect 订阅我的状态,但仍然没有记录更新的状态。

actions.ts

import { createAction } from '@reduxjs/toolkit'

export const setUsername = createAction<string>('auth/setUsername')
export const setPassword = createAction<string>('auth/setPassword')
export const setModalOpen = createAction<boolean>('auth/setModalOpan')

hooks.ts

import { useCallback, useMemo } from 'react'
import { setUsername,setPassword,setModalOpen } from './actions'
import { useSelector, useDispatch } from 'react-redux'
import {IAuth} from './reducer'
import {AppState} from '../index'

export function useSetUsername(): (payload:string)=>void {
  const dispatch = useDispatch()
  return useCallback((payload)=>dispatch(setUsername(payload)), [dispatch])
}

export function useSetPassword(): (payload:string)=>void {
  const dispatch = useDispatch()
  return useCallback((payload)=>dispatch(setPassword(payload)), [dispatch])
}

export function useSetModalOpen(): (payload:boolean)=>void {
  const dispatch = useDispatch()
  return useCallback((payload)=>dispatch(setModalOpen(payload)), [dispatch])
}

export function useGetAuthState():IAuth {
  return useSelector((state:AppState)=>state.payload)
}

reducer.ts

import { createReducer } from '@reduxjs/toolkit'
import {setUsername, setPassword, setModalOpen} from './actions'

export interface IAuth{
  username: string;
  password: string;
  modalOpen: boolean;
}

const initialState:IAuth = {
  username: '',
  password: '',
  modalOpen: false
}

export default createReducer(initialState, builder=>
  builder
.addCase(setUsername, (state ,action)=>{
  state = {...state, username:action.payload}
})
.addCase(setPassword,(state,action)=>{
  state = {...state, password:action.payload}
})
.addCase(setModalOpen,(state,action)=>{
  state = {...state, modalOpen:action.payload}
})
  )

implementation.tsx

import React, {useState, useEffect, useRef, useLayoutEffect} from 'react';
import { Route, Switch, useRouteMatch, useParams} from 'react-router-dom';
import {useSetPassword, useSetUsername, useSetModalOpen, useGetAuthState} from './state/auth/hooks'

function Review():JSX.Element {
  const match = useRouteMatch()
  const authState = useGetAuthState()
  const setUsername = useSetUsername()
  setUsername('why wont this work?')


  function Topic(){
    let {topicId} = useParams<{topicId:string}>()
    console.log(authState)
    console.log(topicId)
    return <>The topic is... {topicId}</>
  }

  function Main(){
    return (
      <div>
        Primary Page
      </div>
    )
  }

  return(
    <Switch>
      <Route path={`${match.path}/:topicId`}>
        <Topic/>
      </Route>
      <Route path={`${match.path}/`}>
        <Main />
      </Route>
    </Switch>
  )
}

export default Review;

我想运行 setUsername(),然后记录 getAuthState() 的结果输出。 当我运行它时,我只是在日志中获得我的默认状态。我已经尝试使用 useEffect 订阅 authState,但这对我来说没有任何改变。

谢谢。

【问题讨论】:

    标签: reactjs redux react-redux redux-toolkit


    【解决方案1】:

    我认为你的问题也在于你的减速器,问题是你正在重新分配 state 变量。您应该直接改变状态草稿对象返回一个新的状态对象。请注意,状态重新分配都不是这些。

    Redux Toolkit Direct State Mutation

    编写“变异”化简器可以简化代码。比较短,有 更少的间接性,它消除了在执行过程中犯的常见错误 传播嵌套状态。但是,使用 Immer 确实增加了一些 “魔法”,而 Immer 在行为上也有自己的细微差别。你应该阅读 通过 immer 文档中提到的陷阱。最重要的是,你 需要确保您改变状态参数或返回 新状态,但不是两者都

    pitfalls mentioned in the immer docs - Don't reassign the recipe argument

    切勿重新分配草稿参数(例如:draft = myCoolNewState)。 相反,要么修改draft,要么返回一个新状态。

    所以你应该改变草案状态:

    export default createReducer(initialState, builder =>
      builder
        .addCase(setUsername, (state, action) => {
          state.username = action.payload;
        })
        .addCase(setPassword,(state, action) => {
          state.password = action.payload;
        })
        .addCase(setModalOpen,(state, action) => {
          state.modalOpen = action.payload;
        })
    );
    

    或者返回新的状态对象:

    export default createReducer(initialState, builder =>
      builder
        .addCase(setUsername, (state, action) => ({
          ...state,
          username: action.payload,
        }))
        .addCase(setPassword,(state, action) => ({
          ...state,
          password: action.payload,
        }))
        .addCase(setModalOpen,(state, action) => ({
          ...state,
          modalOpen: action.payload,
        }))
    );
    

    【讨论】:

      【解决方案2】:

      您需要在每个 addCase 中返回一个状态

      所以把你的reducer改成:

      export const store = createReducer(initialState, (builder) =>
        builder
          .addCase(setUsername, (state, action) => ({
            ...state,
            username: action.payload,
          }))
          .addCase(setPassword, (state, action) => ({
            ...state,
            password: action.payload,
          }))
          .addCase(setModalOpen, (state, action) => ({
            ...state,
            modalOpen: action.payload,
          }))
      );
      

      工作示例:

      【讨论】:

      • state.username = action.payload
      猜你喜欢
      • 2021-10-17
      • 2021-11-07
      • 1970-01-01
      • 1970-01-01
      • 2019-05-07
      • 1970-01-01
      • 1970-01-01
      • 2021-03-29
      • 2019-07-18
      相关资源
      最近更新 更多