使用 createAsyncThunk 和 Redux Toolkit 时状态不会更新
State will not Update when using createAsyncThunk and Redux Toolkit
当使用createAsyncThunk
从我的API获取数据时,我可以读取数据,但状态不会更新。
我在我的文件 userSlice.js
中创建了一个切片,就像这样
userSlice.js
:
export const fetchUserById = createAsyncThunk(
'user/fetchUserById',
async (userId, thunkAPI) => {
let response;
try {
response = await API.getUser, { userID: userId }));
} catch (e) {
console.log(e)
}
return response.data.getUser
}
);
export const userSlice = createSlice({
name: 'user',
initialState: {user: {}},
reducers: {},
},
extraReducers: (builder) => {
builder.addCase(fetchUserById.fulfilled, (state, action) => {
state = {
...state,
user: action.payload
}
});
}
});
export default userSlice.reducer
这是我的商店,store.js
:
import { configureStore } from '@reduxjs/toolkit'
import userReducer from './slices/userSlice'
export default configureStore({
reducer: {
userReducer
}
})
我尝试读取AppLoadingScreen.js
中的数据
AppLoadingScreen.js
:
import AppLoading from 'expo-app-loading';
import React from 'react';
import { useSelector, useDispatch } from 'react-redux'
import { fetchUserById } from '../../redux/slices/userSlice';
const AppLoadingScreen = (props) => {
const user = useSelector(state => state.userReducer.user)
const dispatch = useDispatch()
const cacheResources = async () => {
dispatch(fetchUserById('00'))
.unwrap()
.then((result) => console.log("result: ", result))
.then(console.log("in dispatch: ", user))
.catch((e) => {console.log(e)});
console.log("test: ", user);
}
return (
<AppLoading
startAsync={cacheResources}
onFinish={() => {props.setIsReady(true)}}
onError={console.warn}
/>
);
}
输出:
in dispatch: Object {}
test: Object {}
result: Object {
"firstName": "John",
"lastName": "Doe",
"height": 72,
"age": 40,
}
在这两种情况下,user
都不会更新。即使我将调度调用更改为使用等待,状态也不会改变。
新派遣电话:
const cacheResources = async () => {
await dispatch(fetchUserById('00'));
console.log("test: ", user);
}
新输出:
test: Object {}
我也试过运行 Expo 的 AppLoading 组件外的 dispatch 调用,结果还是一样。
state =
在 RTK Immer 动力减速器中永远不会正确。 Immer 的工作方式是跟踪 突变 到嵌套字段 (state.someField =
),或者从 reducer 函数 (return newState
) 返回一个全新的值。当你写 state =
时,所做的只是将名为 state
的局部变量指向一个新的引用,这既不是突变也不是返回任何东西。
因此,在 Immer 看来,您没有进行任何更改。
这里最简单的答案是写state.user = action.payload
。
有关详细信息,请参阅 RTK Usage Guides: Writing Reducers with Immer。
此外,我们特别推荐not using the word "reducer" in your state structure。相反,您应该设置存储,以便状态键以数据类型命名,例如:
configureStore({
reducer: {
user: userReducer
}
})
当使用createAsyncThunk
从我的API获取数据时,我可以读取数据,但状态不会更新。
我在我的文件 userSlice.js
中创建了一个切片,就像这样
userSlice.js
:
export const fetchUserById = createAsyncThunk(
'user/fetchUserById',
async (userId, thunkAPI) => {
let response;
try {
response = await API.getUser, { userID: userId }));
} catch (e) {
console.log(e)
}
return response.data.getUser
}
);
export const userSlice = createSlice({
name: 'user',
initialState: {user: {}},
reducers: {},
},
extraReducers: (builder) => {
builder.addCase(fetchUserById.fulfilled, (state, action) => {
state = {
...state,
user: action.payload
}
});
}
});
export default userSlice.reducer
这是我的商店,store.js
:
import { configureStore } from '@reduxjs/toolkit'
import userReducer from './slices/userSlice'
export default configureStore({
reducer: {
userReducer
}
})
我尝试读取AppLoadingScreen.js
AppLoadingScreen.js
:
import AppLoading from 'expo-app-loading';
import React from 'react';
import { useSelector, useDispatch } from 'react-redux'
import { fetchUserById } from '../../redux/slices/userSlice';
const AppLoadingScreen = (props) => {
const user = useSelector(state => state.userReducer.user)
const dispatch = useDispatch()
const cacheResources = async () => {
dispatch(fetchUserById('00'))
.unwrap()
.then((result) => console.log("result: ", result))
.then(console.log("in dispatch: ", user))
.catch((e) => {console.log(e)});
console.log("test: ", user);
}
return (
<AppLoading
startAsync={cacheResources}
onFinish={() => {props.setIsReady(true)}}
onError={console.warn}
/>
);
}
输出:
in dispatch: Object {}
test: Object {}
result: Object {
"firstName": "John",
"lastName": "Doe",
"height": 72,
"age": 40,
}
在这两种情况下,user
都不会更新。即使我将调度调用更改为使用等待,状态也不会改变。
新派遣电话:
const cacheResources = async () => {
await dispatch(fetchUserById('00'));
console.log("test: ", user);
}
新输出:
test: Object {}
我也试过运行 Expo 的 AppLoading 组件外的 dispatch 调用,结果还是一样。
state =
在 RTK Immer 动力减速器中永远不会正确。 Immer 的工作方式是跟踪 突变 到嵌套字段 (state.someField =
),或者从 reducer 函数 (return newState
) 返回一个全新的值。当你写 state =
时,所做的只是将名为 state
的局部变量指向一个新的引用,这既不是突变也不是返回任何东西。
因此,在 Immer 看来,您没有进行任何更改。
这里最简单的答案是写state.user = action.payload
。
有关详细信息,请参阅 RTK Usage Guides: Writing Reducers with Immer。
此外,我们特别推荐not using the word "reducer" in your state structure。相反,您应该设置存储,以便状态键以数据类型命名,例如:
configureStore({
reducer: {
user: userReducer
}
})