How to keep React new Context API state when routing between Components?
Asked Answered
B

2

9

Summary:

1) Do you know how to keep the state of a Context Provider present when it is mounted/unmounted through routing? 2) Or do you know a well maintained Flux implementation that supports multiple separated stores?

In detail:

Besides React components own state I've been using mostly redux so far. Besides not loving the idea of having every state managed globally, even though it might only be relevant for a subtree, it also becomes an issue for my new project.

We want to dynamically load components and add them via routing to the app. To be able to have components ready for plug and play, we want them to take care of their own state (store it, request it from the server, provide a strategy to modify it).

I read about how to dynamically add reducers to the global store with redux, but I actually find the approach of Reacts Context API much nicer where I can encapsulate some state in a Provider and can consume it wherever I need it.

The only issue I have is, that a Provider and a Consumer are React components, so if they are part of a component, that is mounted and unmounted through routing, the state that might have been created or fetched once, is gone.

It seems to me that there is no way to solve that, besides temporarily storing the state in the localstorage or on the server. If there is, please let me know!!!

If there shouldn't be a better solution:

I also thought about a more original Flux implementation that would allow multiple stores, which could be encapsulated with the relavant component subtree. But I haven't really found any well maintained Flux implementation besides Redux. Mobx being the exception, but I really prefer the reducer solution of Redux over the observable solution of Mobx. So again, if you know a multi store Flux implementation that is well maintained, please let me know!!!

I would be really happy about some feedback and hope you can point me into a direction that is more satisfiying than dynamic reducer Redux or temporarily persisted Context state.

Thanks a lot in advance!

Bamford answered 10/6, 2018 at 3:25 Comment(0)
H
2

Sorry that it's quite a late answer

Are you using React Router?

The state should be persisted and it shouldn't clear if you are navigating correctly. There should be no page reload as this will cause the state to clear.

Here is an example:

import { Router as RootRouter } from 'react-router-dom';
import Router from './routes/Router';

const App = () => {
    return (
        <MyContext value={useReducer(myReducer, initialState)}>
            <RootRouter history={browserHistory}>
                <Router />
            </RootRouter>
        </AuthContext>
    );
}
import About from '../components/About';

const Router = () => {
    return (
        <Switch>
            <Route exact path='/about' component={About}></Route>
        </Switch>
}

On your main home component, you have to use a Link or Navlink to "switch" between components. Therefore, you'll have something like...

import { Link } from 'react-router-dom';

<Link to="/about">About</Link>

This will navigate you to the about page in which you can still access the context stage where nothing is cleared.

Hochman answered 8/6, 2019 at 9:26 Comment(2)
Is there any way to use the persisted state when using the attribute target="_blank" with the Link tag. I am able to use the persisted state without the target attribute but it comes up as blank when the attribute is added. I need the attribute too since I need to open the following page in a new tab.Creatine
@Creatine If you're opening in a new tab then it will always clear state. What you want is to persist state. The best way to do this is to save it in local storage and then read from it and use whatever you read from local storage as your current state.Hochman
B
0

So I figured out a way to work around the problem with Context (first question): I store the state of the Provider component in a variable. That way, when that component is mounted again, it uses the "persisted" state as the initial value for it's state.

let persistedState = {};
const Context = React.createContext();

export class Provider extends React.PureComponent {

  state = { ...persistedState };

  updateState = (nextState) => this.setState(nextState, () => {
    persistedState = {...this.state};
  });

  render() {
    return (
      <Context.Provider value={this.state}>
        {this.props.children}
      </Context.Provider>
    );
  }
}
Bamford answered 12/6, 2018 at 12:47 Comment(1)
one should always try to avoid using global variables, you will end up creating a messKalidasa

© 2022 - 2024 — McMap. All rights reserved.