最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to save Redux state properly after refreshing the page? - Stack Overflow

programmeradmin1浏览0评论

Code for request:

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 pose(
  graphql(LOG_IN),
  withRouter,
  connect(({ errors }) => ({ error: errors.log_in_error }), {
    logInError,
    logInCleanError,
    logIn,
  })
)(LogInContainer);

Code for 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;
  }
};

I save JWT and put it in the headers for every request like:

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

And I protect my routers like:

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;

After refreshing the page being logged in, I don't lose JWT and stay in the system, but I lose redux state with user's firstname, secondname and etc. which I need to show on the page. So what is the proper way to save redux state in that case without plugins like redux-persist or something else

Code for request:

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 pose(
  graphql(LOG_IN),
  withRouter,
  connect(({ errors }) => ({ error: errors.log_in_error }), {
    logInError,
    logInCleanError,
    logIn,
  })
)(LogInContainer);

Code for 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;
  }
};

I save JWT and put it in the headers for every request like:

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

And I protect my routers like:

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;

After refreshing the page being logged in, I don't lose JWT and stay in the system, but I lose redux state with user's firstname, secondname and etc. which I need to show on the page. So what is the proper way to save redux state in that case without plugins like redux-persist or something else

Share Improve this question asked May 20, 2020 at 19:07 rgdzvrgdzv 5056 silver badges20 bronze badges 1
  • Look at redux-persist – dwjohnston Commented May 24, 2020 at 22:41
Add a ment  | 

4 Answers 4

Reset to default 2

As Dan Abramov suggests you should use the local storage in the store's subscribe method:

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

Before creating the store, read those persisted parts:

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

If you use bineReducers() you’ll notice that reducers that haven’t received the state will “boot up” as normal using their default state argument value. This can be pretty handy.

It is advisable that you debounce your subscriber so you don’t write to localStorage too fast, or you’ll have performance problems.

Finally, you can create a middleware that encapsulates that as an alternative, but I’d start with a subscriber because it’s a simpler solution and does the job well.

发布评论

评论列表(0)

  1. 暂无评论