Redux 不会更新状态
Redux won't update state
我是第一次使用 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,但这对我来说没有任何改变。
谢谢。
您需要 return 每个 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
变量。您应该直接改变状态草案对象 或 return 一个新的状态对象。请注意,状态重新分配不是这些。
Redux Toolkit Direct State Mutation
Writing "mutating" reducers simplifies the code. It's shorter, there's
less indirection, and it eliminates common mistakes made while
spreading nested state. However, the use of Immer does add some
"magic", and Immer has its own nuances in behavior. You should read
through pitfalls mentioned in the immer docs . Most importantly, you
need to ensure that you either mutate the state argument or return a
new state, but not both.
pitfalls mentioned in the immer docs - Don't reassign the recipe argument
Never reassign the draft argument (example: draft = myCoolNewState
).
Instead, either modify the draft
or return a new state.
所以你应该改变草稿状态:
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;
})
);
或return新状态对象:
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,
}))
);
我是第一次使用 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,但这对我来说没有任何改变。
谢谢。
您需要 return 每个 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
变量。您应该直接改变状态草案对象 或 return 一个新的状态对象。请注意,状态重新分配不是这些。
Redux Toolkit Direct State Mutation
Writing "mutating" reducers simplifies the code. It's shorter, there's less indirection, and it eliminates common mistakes made while spreading nested state. However, the use of Immer does add some "magic", and Immer has its own nuances in behavior. You should read through pitfalls mentioned in the immer docs . Most importantly, you need to ensure that you either mutate the state argument or return a new state, but not both.
pitfalls mentioned in the immer docs - Don't reassign the recipe argument
Never reassign the draft argument (example:
draft = myCoolNewState
). Instead, either modify thedraft
or return a new state.
所以你应该改变草稿状态:
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;
})
);
或return新状态对象:
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,
}))
);