2

I'm using context API for state management in a React application and I'm looking for a way to access state in a stateless function from my Provider class.

I'm familiar with wrapping the Consumer tags around the JSX inside render() but in this case, I am not returning any JSX

app.js

export default class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <Provider>
            <Header />
            <Switch>
              <PrivateRoute path='/test' component={test} />
            </Switch>
        </Provider>
      </BrowserRouter>
    );
  };
};

/context/index.js (Provider Class)

import React, { Component } from 'react';
import axios from 'axios';
import {withRouter} from 'react-router';

const AuthContext = React.createContext();

class Provider extends Component {

  state ={
    firstName: '',
    lastName:'',
    emailAddress: '',
    password: '',
    signedIn: false,
  };

  render(){
    return (
      <AuthContext.Provider value = {{
        user: {...this.state},
      }}>
        {this.props.children}
      </AuthContext.Provider>
    );
  };
};

export default withRouter(Provider);
export const Consumer = AuthContext.Consumer;

PrivateRoute.js

import React from 'react';
import { Route } from 'react-router-dom';

const PrivateRoute = ({ component: Component, ...rest}) => {
  <Route {...rest} render = {() => (

  /* I NEED TO CHECK IF USER IS SIGNED IN. HOW DO I ACCESS this.state.signedIn from within the Provider class? */

  )} />
}

export default PrivateRoute

I'm working on a component that needs authentication before accessing the route but first I need to figure out how to pull the state from the Provider class into PrivateRoute.js

learnerforlife
  • 189
  • 1
  • 3
  • 15
  • Here is a better implementation of clear structure of `react context API` [Link to related question](https://stackoverflow.com/questions/69870459/how-to-manage-navbar-state-with-usecontext-react-next-app) – Felix Orinda Nov 07 '21 at 08:10

1 Answers1

3

You can wrap the PrivateRoute inside another anonymous function which uses context as a render prop and pass it on to the PrivateRoute though props like

import React from 'react';
import { Route } from 'react-router-dom';

const PrivateRoute = ({ component: Component, context, ...rest}) => {
  return <Route {...rest} render = {() => (

     /* use `context.signedIn` from within the Provider class? */

  )} />
}

export default () => <Consumer>{(context) => <PrivateRoute context={context} />}</Consumer>

Or if you are using v16.8.0 or above of react, you can make use of useContext hook

import React, { useContext } from 'react';
import { Route } from 'react-router-dom';

const PrivateRoute = ({ component: Component, context, ...rest}) => { 
  const context = useContext(AuthContext);
  return <Route {...rest} render = {() => (

     /* use `context.signedIn` from within the Provider class? */

  )} />
}
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • Couldn't get your first solution to work. If context.signedIn was false, It redirected to a sign in page with no issues but once I was signed in, there were errors when rendering to my desired component. The console errors I got where along the lines of `The error occured in " "Warning: React.createElement: type is invalid --expected a string or a class/function but got undefined. Likely forgot to export your component from the file its defined in or mixed up default and named imports` Your second solution (useContext) works with no issues – learnerforlife Apr 22 '19 at 21:40