#react-native #react-redux #redux-saga
Вопрос:
При вызове API я сохраняю свой токен в своей саге о переделке следующим образом:
export function* onLoginUser(payload) {
try {
const response = yield call(loginUserApi, payload.user);
if (response) {
yield call(storeToken, response.data.token.api_token);
yield put(loginUserSuccess(response.data));
}
} catch (error) {
yield put({type: type.LOGIN_USER_ERROR, error});
}
}
async function storeToken(token) {
try {
await AsyncStorage.setItem('token', token);
} catch (error) {
console.log('AsyncStorage error during token store:', error);
}
}
На данный момент я считаю, что мне удалось сохранить свой токен в AsyncStorage.
Теперь в моей логинформ. Мне нужно проверить, был ли токен сохранен или существует в AsyncStorage ПОСЛЕ нажатия кнопки «Отправить». Очевидно, что он не будет существовать до тех пор, пока не будет нажата кнопка отправить:
const dispatch = useDispatch();
const submitHandler = (val: any) => {
dispatch(loginUserAction(val));
};
onSubmit={values => submitHandler(values)}
Теперь я хочу проверить, существует ли он ПОСЛЕ кнопки «Отправить», а затем что-то сделать. Так что я сделал вот что:
const checkUserSignedIn = async () => {
try {
let value = await AsyncStorage.getItem('token');
if (value != null) {
navigateTo('HomeScreen');
}
} catch (error) {
console.log(error);
}
};
useEffect(() => {
checkUserSignedIn();
});
Однако использование useEffect
не будет работать после нажатия кнопки. Как я могу убедиться, что это вызов ПОСЛЕ нажатия кнопки? Правильно ли я это делаю?
Ответ №1:
Есть еще много способов достичь этого. Что я бы вам рекомендовал, так это добавить loading
параметр в состояние входа в систему redux.
Таким образом, начальное состояние должно быть примерно таким
state: {
...otherStates,
loginState: {
...yourState,
loading: false,
data: null
}
}
Затем вы вызываете свое действие loginUserAction
с дополнительным параметром loading: true
, который изменяет начальное значение через соответствующий редуктор.
В своей саге вы обновляете свой призыв к успеху следующим образом:
yield put(loginUserSuccess({data: response.data, loading: false}));
Имейте в виду, что блок catch в вашей саге loading: false
тоже должен быть, иначе вы можете закончить, loading: true
даже когда вызов саги уже завершен. Также не забывайте правильно подключать действия к редукторам.
Наконец, вы хотите использовать крюк селектора для получения обновленных данных в вашем компоненте.
Пример: const { loading, data } = useSelector((state) => state.loginState)
/* You want to store data and get some too so when it changes you actually know if it was updated successfully. Shortly loading: true/false alone is not enough as source of truth */
Теперь ваш компонент будет прослушивать loading
и data
поддерживать. Чтобы достичь того, чего вы хотите, вы можете просто использовать условие сейчас.
useEffect(() => {
if(!loading amp;amp; data !== null) {
checkUserSignedIn()
}
}, [loading, data])
И последнее, добавьте Throw
функцию внутри блока catch storeToken
, потому что теперь, если она попадет внутрь блока catch, console.log
это не вызовет сбоя в saga call()
, и это будет продолжаться yield put(loginUserSuccess(response.data));
, но ваши данные вообще не будут сохранены 🙂