Javascript 为什么React/redux状态在刷新时重置?
当我登录时,一切正常,但当我点击刷新或导航到其他地方时,状态被重置。知道为什么吗?我希望能够引用该州的用户,并获得诸如名称等信息,并在组件中使用它。但它只有在我登录后才能工作,然后它就会重置 还有,为什么我必须使用.进入MapStateTops?如果没有,我会得到一个贴图对象。是因为IMMUTABLE.JS吗 这是我的app.js文件Javascript 为什么React/redux状态在刷新时重置?,javascript,reactjs,redux,react-redux,immutable.js,Javascript,Reactjs,Redux,React Redux,Immutable.js,当我登录时,一切正常,但当我点击刷新或导航到其他地方时,状态被重置。知道为什么吗?我希望能够引用该州的用户,并获得诸如名称等信息,并在组件中使用它。但它只有在我登录后才能工作,然后它就会重置 还有,为什么我必须使用.进入MapStateTops?如果没有,我会得到一个贴图对象。是因为IMMUTABLE.JS吗 这是我的app.js文件 /** * app.js * * This is the entry file for the application, only setup and bo
/**
* app.js
*
* This is the entry file for the application, only setup and boilerplate
* code.
*/
// Needed for redux-saga es6 generator support
import '@babel/polyfill';
// Import all the third party stuff
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'connected-react-router/immutable';
import jwt_decode from 'jwt-decode';
import FontFaceObserver from 'fontfaceobserver';
import history from 'utils/history';
import 'sanitize.css/sanitize.css';
// Import root app
import App from 'containers/App';
import './styles/layout/base.scss';
// Import Language Provider
import LanguageProvider from 'containers/LanguageProvider';
import { setCurrentUser, logoutUser } from './redux/actions/authActions';
import setAuthToken from './utils/setAuthToken';
// Load the favicon and the .htaccess file
import '!file-loader?name=[name].[ext]!../public/favicons/favicon.ico'; // eslint-disable-line
import 'file-loader?name=.htaccess!./.htaccess'; // eslint-disable-line
import configureStore from './redux/configureStore';
// Import i18n messages
import { translationMessages } from './i18n';
// Check for token to keep user logged in
if (localStorage.jwtToken) {
// Set auth token header auth
const token = JSON.parse(localStorage.jwtToken);
setAuthToken(token);
// Decode token and get user info and exp
const decoded = jwt_decode(token);
console.log(decoded);
// Set user and isAuthenticated
setCurrentUser(decoded);
// Check for expired token
const currentTime = Date.now() / 1000; // to get in milliseconds
if (decoded.exp < currentTime) {
// Logout user
logoutUser();
// Redirect to login
window.location.href = './';
}
}
// Observe loading of Open Sans (to remove open sans, remove the <link> tag in
// the index.html file and this observer)
const openSansObserver = new FontFaceObserver('Open Sans', {});
// When Open Sans is loaded, add a font-family using Open Sans to the body
openSansObserver.load().then(() => {
document.body.classList.add('fontLoaded');
});
// Create redux store with history
const initialState = {};
const store = configureStore(initialState, history);
const MOUNT_NODE = document.getElementById('app');
const render = messages => {
ReactDOM.render(
<Provider store={store}>
<LanguageProvider messages={messages}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</LanguageProvider>
</Provider>,
MOUNT_NODE,
);
};
if (module.hot) {
// Hot reloadable React components and translation json files
// modules.hot.accept does not accept dynamic dependencies,
// have to be constants at compile-time
module.hot.accept(['./i18n', 'containers/App'], () => {
ReactDOM.unmountComponentAtNode(MOUNT_NODE);
render(translationMessages);
});
}
// Chunked polyfill for browsers without Intl support
if (!window.Intl) {
new Promise(resolve => {
resolve(import('intl'));
})
.then(() =>
Promise.all([import('intl/locale-data/jsonp/en.js'), import('intl/locale-data/jsonp/de.js')]),
) // eslint-disable-line prettier/prettier
.then(() => render(translationMessages))
.catch(err => {
throw err;
});
} else {
render(translationMessages);
}
// Install ServiceWorker and AppCache in the end since
// it's not most important operation and if main code fails,
// we do not want it installed
if (process.env.NODE_ENV === 'production') {
require('offline-plugin/runtime').install(); // eslint-disable-line global-require
}
EDIT:当我查看redux devtools时,我看到IF块在每次刷新时都会运行,但正确的状态似乎不会传递给其他组件。其他组件在第一次获得正确的状态(isAuthenticated:true),但一旦我刷新,它们就会返回false。在redux开发工具中,我每次刷新时都会看到这一点。
主减速器
/**
* Combine all reducers in this file and export the combined reducers.
*/
import { reducer as form } from 'redux-form/immutable';
import { combineReducers } from 'redux-immutable';
import { connectRouter } from 'connected-react-router/immutable';
import history from 'utils/history';
import languageProviderReducer from 'containers/LanguageProvider/reducer';
import uiReducer from './modules/ui';
import initval from './modules/initForm';
import login from './modules/login';
import treeTable from '../containers/Tables/reducers/treeTbReducer';
import crudTable from '../containers/Tables/reducers/crudTbReducer';
import crudTableForm from '../containers/Tables/reducers/crudTbFrmReducer';
import ecommerce from '../containers/SampleApps/Ecommerce/reducers/ecommerceReducer';
import contact from '../containers/SampleApps/Contact/reducers/contactReducer';
import chat from '../containers/SampleApps/Chat/reducers/chatReducer';
import email from '../containers/SampleApps/Email/reducers/emailReducer';
import calendar from '../containers/SampleApps/Calendar/reducers/calendarReducer';
import socmed from '../containers/SampleApps/Timeline/reducers/timelineReducer';
import taskboard from '../containers/SampleApps/TaskBoard/reducers/taskboardReducer';
/**
* Branching reducers to use one reducer for many components
*/
function branchReducer(reducerFunction, reducerName) {
return (state, action) => {
const { branch } = action;
const isInitializationCall = state === undefined;
if (branch !== reducerName && !isInitializationCall) {
return state;
}
return reducerFunction(state, action);
};
}
/**
* Merges the main reducer with the router state and dynamically injected reducers
*/
export default function createReducer(injectedReducers = {}) {
const rootReducer = combineReducers({
form,
ui: uiReducer,
initval,
login,
socmed,
calendar,
ecommerce,
contact,
chat,
email,
taskboard,
treeTableArrow: branchReducer(treeTable, 'treeTableArrow'),
treeTablePM: branchReducer(treeTable, 'treeTablePM'),
crudTableDemo: branchReducer(crudTable, 'crudTableDemo'),
crudTableForm,
crudTbFrmDemo: branchReducer(crudTableForm, 'crudTbFrmDemo'),
language: languageProviderReducer,
router: connectRouter(history),
...injectedReducers,
});
// Wrap the root reducer and return a new root reducer with router state
const mergeWithRouterState = connectRouter(history);
return mergeWithRouterState(rootReducer);
}
createStore.js
/**
* Create the store with dynamic reducers
*/
import { createStore, applyMiddleware, compose } from 'redux';
import { routerMiddleware } from 'connected-react-router';
import { fromJS } from 'immutable';
import createSagaMiddleware from 'redux-saga';
import thunk from 'redux-thunk';
import createReducer from './reducers';
export default function configureStore(initialState = {}, history) {
let composeEnhancers = compose;
const reduxSagaMonitorOptions = {};
// If Redux Dev Tools and Saga Dev Tools Extensions are installed, enable them
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'production' && typeof window === 'object') {
/* eslint-disable no-underscore-dangle */
if (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true });
}
// NOTE: Uncomment the code below to restore support for Redux Saga
// Dev Tools once it supports redux-saga version 1.x.x
if (window.__SAGA_MONITOR_EXTENSION__)
reduxSagaMonitorOptions = {
sagaMonitor: window.__SAGA_MONITOR_EXTENSION__,
};
/* eslint-enable */
}
const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions);
// Create the store with two middlewares
// 1. sagaMiddleware: Makes redux-sagas work
// 2. routerMiddleware: Syncs the location/URL path to the state
const middleware = [thunk];
const middlewares = [...middleware, sagaMiddleware, routerMiddleware(history)];
const enhancers = [applyMiddleware(...middlewares)];
const store = createStore(createReducer(), fromJS(initialState), composeEnhancers(...enhancers));
// Extensions
store.runSaga = sagaMiddleware.run;
store.injectedReducers = {}; // Reducer registry
store.injectedSagas = {}; // Saga registry
// Make reducers hot reloadable, see http://mxs.is/googmo
/* istanbul ignore next */
if (module.hot) {
module.hot.accept('./reducers', () => {
store.replaceReducer(createReducer(store.injectedReducers));
});
}
return store;
}
主应用程序文件
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import NotFound from 'containers/Pages/Standalone/NotFoundDedicated';
import jwtDecode from 'jwt-decode';
import configureStore from '../../redux/configureStore';
import { setCurrentUser, logoutUser } from '../../redux/actions/authActions';
import setAuthToken from '../../utils/setAuthToken';
import Auth from './Auth';
import Application from './Application';
import ThemeWrapper, { AppContext } from './ThemeWrapper';
import { PrivateRoute } from './PrivateRoute';
window.__MUI_USE_NEXT_TYPOGRAPHY_VARIANTS__ = true;
const initialState = {};
const store = configureStore(initialState);
const auth = localStorage.jwtToken ? true : false;
// Check for token to keep user logged in
if (localStorage.jwtToken) {
// Set auth token header auth
const token = JSON.parse(localStorage.jwtToken);
setAuthToken(token);
// Decode token and get user info and exp
const decoded = jwtDecode(token);
// Set user and isAuthenticated
store.dispatch(setCurrentUser(decoded));
// Check for expired token
const currentTime = Date.now() / 1000; // to get in milliseconds
if (decoded.exp < currentTime) {
// Logout user
logoutUser();
// Redirect to login
window.location.href = './';
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
errors: {},
};
}
render() {
return (
<ThemeWrapper>
<AppContext.Consumer>
{changeMode => (
<Switch>
{/* <Route path="/" exact component={Login} /> */}
<PrivateRoute
path="/app"
auth={auth}
component={props => <Application {...props} changeMode={changeMode} />}
/>
<Route component={Auth} />
<Route component={NotFound} />
</Switch>
)}
</AppContext.Consumer>
</ThemeWrapper>
);
}
}
export default App;
使用persistedState。这是index.js文件示例
function saveToLocalStorage(state) {
try {
const serializedState = JSON.stringify(state)
localStorage.setItem('state', serializedState)
} catch (err) {
console.log(err)
}
}
function loadFromLocalStorage() {
try {
const serializedState = localStorage.getItem('state');
if (serializedState === null) return undefined;
return JSON.parse(serializedState)
} catch (err) {
console.log(err)
return undefined;
}
}
const persistedState = loadFromLocalStorage();
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
reducer,
persistedState,
applyMiddleware(logger, sagaMiddleware))
sagaMiddleware.run(watchLoadData);
store.subscribe(() => saveToLocalStorage(store.getState()))
ReactDOM.render(
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>,
document.getElementById('root')
);
函数saveToLocalStorage(状态){
试一试{
const serializedState=JSON.stringify(状态)
localStorage.setItem('state',serializedState)
}捕捉(错误){
console.log(错误)
}
}
函数loadFromLocalStorage(){
试一试{
const serializedState=localStorage.getItem('state');
if(serializedState==null)返回undefined;
返回JSON.parse(serializedState)
}捕捉(错误){
console.log(错误)
返回未定义;
}
}
const persistedState=loadFromLocalStorage();
const sagaMiddleware=createSagaMiddleware();
const store=createStore(
减速器,
持续状态,
applyMiddleware(记录器、sagaMiddleware))
sagaMiddleware.run(watchLoadData);
store.subscribe(()=>saveToLocalStorage(store.getState()))
ReactDOM.render(
,
document.getElementById('root'))
);
您可以使用在刷新后保持状态。可能有帮助。应用程序的状态存储在存储区中的嵌套对象中。因此,当您刷新页面时,由于应用程序会重新加载内存,因此对象会重置为初始值。if语句是否应该在每次刷新页面和更新状态时重新运行?if语句是否应该在每次刷新页面和更新状态时重新运行?实际上,这似乎是可行的,但是为什么当我使用console.log(localStorage.state)时,我会得到这个“{\'contact\”:{\'formValues\”:{},\'keywordValue\:\”,\'avatarInit\:\”,\'showMobileDetail\”:false,\'notifMsg\“:\”,\'selectedId\:“,'openFrm\:false,\'selectedIndex\:0,\'contactList\:[],'ecommerce\:”如何返回一个可用的格式?不管怎样,我得到了JSON.parse。但是状态仍然会被重置。即使在我查看localstorage时,在重新加载页面后,状态也是重置的。请执行以下操作const initialState={id:localstorage.getItem('id'),email:localstorage.getItem('email')),名称:localStorage.getItem('name'),标记:localStorage.getItem('token'),authStatus:localStorage.getItem('authStatus'),errorMessage:'}
执行此操作时使所有值为空
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import NotFound from 'containers/Pages/Standalone/NotFoundDedicated';
import jwtDecode from 'jwt-decode';
import configureStore from '../../redux/configureStore';
import { setCurrentUser, logoutUser } from '../../redux/actions/authActions';
import setAuthToken from '../../utils/setAuthToken';
import Auth from './Auth';
import Application from './Application';
import ThemeWrapper, { AppContext } from './ThemeWrapper';
import { PrivateRoute } from './PrivateRoute';
window.__MUI_USE_NEXT_TYPOGRAPHY_VARIANTS__ = true;
const initialState = {};
const store = configureStore(initialState);
const auth = localStorage.jwtToken ? true : false;
// Check for token to keep user logged in
if (localStorage.jwtToken) {
// Set auth token header auth
const token = JSON.parse(localStorage.jwtToken);
setAuthToken(token);
// Decode token and get user info and exp
const decoded = jwtDecode(token);
// Set user and isAuthenticated
store.dispatch(setCurrentUser(decoded));
// Check for expired token
const currentTime = Date.now() / 1000; // to get in milliseconds
if (decoded.exp < currentTime) {
// Logout user
logoutUser();
// Redirect to login
window.location.href = './';
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
errors: {},
};
}
render() {
return (
<ThemeWrapper>
<AppContext.Consumer>
{changeMode => (
<Switch>
{/* <Route path="/" exact component={Login} /> */}
<PrivateRoute
path="/app"
auth={auth}
component={props => <Application {...props} changeMode={changeMode} />}
/>
<Route component={Auth} />
<Route component={NotFound} />
</Switch>
)}
</AppContext.Consumer>
</ThemeWrapper>
);
}
}
export default App;
import React from 'react';
import hoistNonReactStatics from 'hoist-non-react-statics';
import { ReactReduxContext } from 'react-redux';
import getInjectors from './reducerInjectors';
/**
* Dynamically injects a reducer
*
* @param {string} key A key of the reducer
* @param {function} reducer A reducer that will be injected
*
*/
export default ({ key, reducer }) => WrappedComponent => {
class ReducerInjector extends React.Component {
static WrappedComponent = WrappedComponent;
static contextType = ReactReduxContext;
static displayName = `withReducer(${WrappedComponent.displayName ||
WrappedComponent.name ||
'Component'})`;
constructor(props, context) {
super(props, context);
getInjectors(context.store).injectReducer(key, reducer);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
return hoistNonReactStatics(ReducerInjector, WrappedComponent);
};
const useInjectReducer = ({ key, reducer }) => {
const context = React.useContext(ReactReduxContext);
React.useEffect(() => {
getInjectors(context.store).injectReducer(key, reducer);
}, []);
};
export { useInjectReducer };
import invariant from 'invariant';
import { isEmpty, isFunction, isString } from 'lodash';
import checkStore from './checkStore';
import createReducer from '../redux/reducers';
export function injectReducerFactory(store, isValid) {
return function injectReducer(key, reducer) {
if (!isValid) checkStore(store);
invariant(
isString(key) && !isEmpty(key) && isFunction(reducer),
'(app/utils...) injectReducer: Expected `reducer` to be a reducer function',
);
// Check `store.injectedReducers[key] === reducer` for hot reloading when a key is the same but a reducer is different
if (
Reflect.has(store.injectedReducers, key)
&& store.injectedReducers[key] === reducer
) return;
store.injectedReducers[key] = reducer; // eslint-disable-line no-param-reassign
store.replaceReducer(createReducer(store.injectedReducers));
};
}
export default function getInjectors(store) {
checkStore(store);
return {
injectReducer: injectReducerFactory(store, true),
};
}
function saveToLocalStorage(state) {
try {
const serializedState = JSON.stringify(state)
localStorage.setItem('state', serializedState)
} catch (err) {
console.log(err)
}
}
function loadFromLocalStorage() {
try {
const serializedState = localStorage.getItem('state');
if (serializedState === null) return undefined;
return JSON.parse(serializedState)
} catch (err) {
console.log(err)
return undefined;
}
}
const persistedState = loadFromLocalStorage();
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
reducer,
persistedState,
applyMiddleware(logger, sagaMiddleware))
sagaMiddleware.run(watchLoadData);
store.subscribe(() => saveToLocalStorage(store.getState()))
ReactDOM.render(
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>,
document.getElementById('root')
);