刷新页面后如何正确保存Redux状态?

时间:2020-05-20 19:07:34

标签: javascript reactjs redux apollo-client

请求代码:

export class LogInContainer extends Component {

  submit = (values) => {
    const { mutate } = this.props;
    mutate({
      variables: {
        email: values.email,
        password: values.password,
      },
    })
      .then((res) => {
        const token = res.data.login.token;
        localStorage.setItem("token", token);
        const user = res.data.login.user;
        const { logIn } = this.props;
        logIn(user);
        this.props.history.push("/pages/processes");
      })
      .catch((error) => {
        const errorMessage = error.message;
        const { logInError } = this.props;
        logInError(errorMessage);
      });
  };

  render() {
    const { error, logInCleanError } = this.props;
    return (
      <LogIn
        onSubmit={this.submit}
        errorMessage={error}
        logInCleanError={logInCleanError}
      />
    );
  }
}

export default compose(
  graphql(LOG_IN),
  withRouter,
  connect(({ errors }) => ({ error: errors.log_in_error }), {
    logInError,
    logInCleanError,
    logIn,
  })
)(LogInContainer);

减速器代码:

const initialState = {
  user: {
    id: "",
    firstName: "",
    secondName: "",
    email: "",
    isAuth: localStorage.getItem('token') ? true : false,
  },
};

export const userReducer = (state = initialState, { type, user }) => {
  switch (type) {
    case LOG_IN:
      return {
        ...state,
        user: {
          id: user.id,
          firstName: user.firstName,
          secondName: user.secondName,
          email: user.email,
          isAuth: true,
        },
      };
    case CURRENT_USER:
      return {
        ...state,
        user: {
          id: user.id,
          firstName: user.firstName,
          secondName: user.secondName,
          email: user.email,
          isAuth: true,
        },
      };
    case LOG_OUT:
      return {
        ...state,
        user: {
          id: "",
          firstName: "",
          secondName: "",
          email: "",
          isAuth: false,
        },
      };
    default:
      return state;
  }
};

我保存JWT并将其放在每个请求的标头中,例如:

const client = new ApolloClient({
  uri: "http://localhost:4000/api",
  request: (operation) => {
    const token = localStorage.getItem("token");
    operation.setContext({
      headers: {
        authorization: token ? `Bearer ${token}` : "",
      },
    });
  },
}); 

我可以像这样保护路由器:

const App = ({ authorized }) => {
  return (
    <Switch>
      {!authorized ? (
        <Route path="/auth">
          <Auth />
        </Route>
      ) : (
        <Route path="/pages">
          <Pages />
        </Route>
      )}
      <Redirect from="/" to="/auth/login" />
    </Switch>
  );
};

export default App;

刷新登录页面后,我不会丢失JWT并留在系统中,但是会丢失用户名,第二名等的redux状态,需要在页面上显示该状态。那么,在这种情况下,如果没有类似redux-persist之类的插件

,保存redux状态的正确方法是什么?

4 个答案:

答案 0 :(得分:1)

作为Dan Abramov suggests,您应该在local storage方法中使用store's subscribe

store.subscribe(() => {
  // persist your state
})

在创建商店之前,请阅读以下保留的部分:

const persistedState = // ...
const store = createStore(reducer, persistedState)

如果使用combineReducers(),您会发现减速器没有 接收到的状态将使用其默认的state正常“启动” 参数值。这可能非常方便。

建议您对订户进行反跳操作,以便不要写 到localStorage的速度太快,否则您会遇到性能问题。

最后,您可以创建一个中间件,将其封装为 另一种选择,但我将从订户开始,因为它更简单 解决方案,并且做得很好。

答案 1 :(得分:0)

使用localStorage:

localStorage.setItem('token', token);

并在应用程序加载时检查是否设置了令牌,如果已设置,则从localStorage获取信息

localStorage.getItem('token');

您还可以保存用户信息:

localStorage.setItem('user', JSON.stringify(userInfo));

并使用JSON.parse获取它。

答案 2 :(得分:0)

即使在刷新后仍可以保存Redux状态的整洁方法

它就像一种魅力。

https://www.npmjs.com/package/redux-persist

答案 3 :(得分:0)

?不久

做到这一点:

const initialState = {
  user: {
    id: localStorage.getItem('id') || '',
    firstName: localStorage.getItem('firstName') || '',
    secondName: localStorage.getItem('secondName') || '',
    email: localStorage.getItem('email') || '',
    isAuth: localStorage.getItem('token') ? true : false,
  },
}

?有点复杂但可扩展的方式

创建一个middleware,它将服务与应用程序持久状态相关的所有内容。您可以在那里将数据保存到localStorage,cookie或IndexedDB。中间件,我们称它为LocalStoreMiddleware,它将监听您的redux reducer所做的相同操作,无论每个中间件在何处以及由谁(组件,Saga,Socket)分派操作,何时分发操作,reduce都会更新redux存储, LocalStoreMiddleware会将数据保存到localStorage,cookie,indexDB等。

优势

  • 没有严格的依赖关系
  • 易于扩展
  • 一个域业务逻辑的一席之地
  • 你让纳尼亚世界的一些精灵开心

创建一个文件,您将在其中存储与持久数据相关的功能

// local-store-resolvers.js
import {on} from './local-store-middleware.js'

function saveToken(action, state) {
  localStorage.setItem('token', JSON.stringify(state.token));
}

function saveUsername(action) {
  localStorage.setItem('username', JSON.stringify(action.username));
}

export default [
  on(AUTHORIZATION, saveToken),
  on(USERNAME_CHANGED, saveUsername),
]

中间件工厂

// local-store-middleware.js
export const on = (actionType, resolver) => (action, state) => (
  actionType === action.type && resolver(action, state)
)

const createLocalStoreMiddleware = resolvers => store => next => action => {
  resolvers.forEach(
    resolver => resolver(action, store.getState())
  )
  return next(action)
}

export default createLocalStoreMiddleware

Redux商店

// src/store/index.js - your main file where you create redux store
import createLocalStoreMiddleware from './local-store-middleware.js'
import resolvers from './local-store-resolvers.js'

const localStore = createLocalStoreMiddleware(resolvers)

const store = createStore(
  combineReducers({users, someOtherReducer}),
  applyMiddleware(localStore), // if you have more middlewares use compose
)

export default store