#javascript #reactjs #redux #react-redux #react-hooks
Вопрос:
Я выполняю вызов API в крючке useEffect, а затем сохраняю данные в хранилище redux. Из магазина redux я сохраняю данные в локальном хранилище браузера, выполнив вызов useSelector для получения данных из магазина redux.
Как заставить useSelector вызывать только после того, как данные будут готовы из API.
import React, { useEffect, useState } from "react";
import Navbar from "./Navbar";
import Footer from "./Footer";
import HomeMenu from './HomeMenu';
import { fetchingInPending, fetchingSuccess, fetchingFailed } from './HomeSlice';
import { useSelector, useDispatch } from 'react-redux';
const Home = () => {
const dispatch = useDispatch();
useEffect(() => {
(async () => {
dispatch(fetchingInPending());
const response = await fetch("https://localhost:44316/api/auth/getuser", {
headers: {
"Content-Type": "application/json"
},
credentials: "include",
});
if(response.status === 200){
const content = await response.json();
dispatch(fetchingSuccess({name: content.name, role: content.role}));
}
else{
dispatch(fetchingFailed());
}
})();
},[]);
localStorage.setItem('user', JSON.stringify(useSelector(state => state.userDetails)));
const user = localStorage.getItem('user');
console.log(user);
return (
<React.Fragment>
<h1>Home</h1>
</React.Fragment>
)};
Домашняя мокрица
import { createSlice } from "@reduxjs/toolkit";
export const homeSlice = createSlice({
name: "userDetails",
initialState: {
name: "",
role: "",
isLoading: false
},
reducers: {
fetchingInPending: (state) => {
state.isLoading = true;
},
fetchingSuccess: (state, action) => {
state.name = action.payload.name;
state.role = action.payload.role;
state.isLoading = false;
state.error = "";
},
fetchingFailed: (state, action) => {
state.isLoading = false;
state.error = action.payload.error;
},
},
});
export const { fetchingInPending, fetchingSuccess, fetchingFailed } = homeSlice.actions;
export default homeSlice.reducer;
На консоли моего браузера я получаю данные после трех звонков.
Index.js содержать:
Index.js code:
import React from 'react';
import ReactDOM from 'react-dom';
import './style/index.css';
import App from './App';
import { BrowserRouter} from 'react-router-dom';
import store from './store';
import { Provider } from 'react-redux';
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
Комментарии:
1. вы не можете условно вызывать крючки. Ознакомьтесь с правилами здесь . Вместо этого вы можете использовать
optional chaining
, когда получите состояние наuseSelector
таких:const user = useSelector(state => state.user?.name?.email)
. вы можете прочитать о дополнительной цепочке здесь .2. Я попробовал твой код. Я не обнаружил никаких проблем.. Я думаю, что эта проблема возникает не из-за useSelector. пожалуйста, проверьте index.js. На вашем скриншоте изображена проблема в index.js.. пожалуйста, опубликуйте свой index.js код.
3. обновлено с index.js код
4. В этом есть смысл. Существует три состояния: начальное состояние, ожидающее состояние, состояние выполнения/отклоненное состояние. Вы можете визуализировать разные вещи на основе этих состояний. Итак, что ты хочешь сделать?
Ответ №1:
Я думаю, что @slideshowp2 верен, но для неверных рассуждений. Не выполняется никаких асинхронных действий (т. Е. громких или подобных), поэтому нет возвращенных обещаний, которые должны быть выполнены.
Ваш код
- Регистрирует начальное состояние
- Регистрирует состояние после
dispatch(fetchingInPending());
- Регистрирует третье обновление состояния после
dispatch(fetchingSuccess({ name: content.name, role: content.role }));
Вы не можете условно вызывать крючки реакции, поэтому ваш код правильно сохраняет каждое обновление состояния в localStorage.
Если вы хотите условно сохранить данные в локальном хранилище, поместите эту логику в другой useEffect
хук с зависимостью от состояния redux. Условие состоит в том, чтобы убедиться, что значения из вашего хранилища redux были заполнены.
const userDetails = useSelector(state => state.userDetails);
...
useEffect(() => {
const { name, role } = userDetails;
if (name amp;amp; role) {
localStorage.setItem('user', JSON.stringify({ name, role }));
}
}, [userDetails]);
В качестве альтернативы вы можете просто применить сохранение локального хранилища прямо в существующем useEffect
. Здесь вы сохраняетесь в локальном хранилище только при отправке действия «Успех»
useEffect(() => {
(async () => {
dispatch(fetchingInPending());
const response = await fetch("https://localhost:44316/api/auth/getuser", {
headers: {
"Content-Type": "application/json"
},
credentials: "include",
});
if(response.status === 200){
const { name, role } = await response.json();
const userDetails = { name, role };
dispatch(fetchingSuccess(userDetails)); // <-- dispatch user details
localStorage.setItem( // <-- persist user details
'user',
JSON.stringify(userDetails)
);
}
else{
dispatch(fetchingFailed());
}
})();
},[]);