#react-native #redux #redux-toolkit
#react-native #redux #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
не обновляется. Даже если я изменю вызов отправки на использование await, состояние не изменится.
Новый вызов отправки:
const cacheResources = async () => {
await dispatch(fetchUserById('00'));
console.log("test: ", user);
}
Новый вывод:
test: Object {}
Я также попытался запустить вызов отправки вне компонента загрузки приложений Expo, и результат все тот же.
Ответ №1:
state =
в RTK Immer-powered reducer никогда не корректен. Immer работает, отслеживая мутации во вложенных полях ( state.someField =
) или возвращая совершенно новое значение из функции reducer ( return newState
) . Когда вы пишете state =
, все, что делает, это указывает локальную переменную с именем state
на новую ссылку, которая не является ни мутацией, ни возвратом чего-либо.
Итак, насколько я могу видеть, вы ничего не изменили.
Самый простой ответ здесь — написать state.user = action.payload
.
Более подробную информацию см. В Руководстве по использованию RTK: написание редукторов с помощью Immer.
Кроме того, мы специально рекомендуем не использовать слово «редуктор» в вашей структуре состояний. Вместо этого вы должны настроить хранилище так, чтобы ключи состояния были названы в честь типов данных, например:
configureStore({
reducer: {
user: userReducer
}
})
Комментарии:
1. Я изменил
userSlice.js
, чтобы использовать оператор возврата вместо использованияstate=
. Кроме того, я добавил псевдоним user в userReducer. Теперь, когда я консольный журнал пользователя вне файлаAppLoading.js
, я могу видеть информацию из моего вызова API. Однако журнал консоли внутриAppLoading.js
остается пустым. Для меня это не настоящая проблема, но вы случайно не знаете, почему это происходит?2. Похоже, ваша цепочка обещаний написана неправильно. У вас есть
.then(console.log())
, но это будет немедленно зарегистрировано. Вам нужно обернуть это в функцию со стрелкой. Лично я бы написал.then()
функцию со стрелкой, у которой есть{ }
тело и обе строки журнала внутри него.