【问题标题】:How to save Redux state properly after refreshing the page?刷新页面后如何正确保存 Redux 状态?
【发布时间】:2020-09-07 06:52:13
【问题描述】:

请求代码:

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);

reducer 代码:

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 状态的正确方法是什么

【问题讨论】:

  • redux-persist

标签: javascript reactjs redux apollo-client


【解决方案1】:

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

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

在创建商店之前,请阅读那些持久化的部分:

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

如果你使用combineReducers(),你会注意到没有 收到状态将使用默认state正常“启动” 参数值。这可能非常方便。

建议您去抖动您的订阅者,这样您就不会写 到 localStorage 的速度太快,否则会出现性能问题。

最后,您可以创建一个中间件,将其封装为 替代方案,但我会从订阅者开始,因为它更简单 解决方案并做好工作。

【讨论】:

    【解决方案2】:

    使用本地存储:

    localStorage.setItem('token', token);
    

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

    localStorage.getItem('token');
    

    您还可以保存用户信息:

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

    并使用 JSON.parse 获取它。

    【讨论】:

      【解决方案3】:

      即使在刷新后也能保存 redux 状态的简洁的解决方案是 Redux persist。

      它就像一个魅力。

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

      【讨论】:

      • 项目不再维护 :(
      【解决方案4】:

      ?马上

      做这个:

      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 reducers 所做的相同动作,当一个动作将被分派时,无论在哪里和由谁(组件,Saga,Socket)每个中间件都会完成他们负责的工作,reducers 将更新 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
      

      【讨论】:

        猜你喜欢
        • 2018-07-25
        • 1970-01-01
        • 2019-01-20
        • 1970-01-01
        • 1970-01-01
        • 2019-05-19
        • 1970-01-01
        • 2021-02-12
        • 2023-02-26
        相关资源
        最近更新 更多