I'm trying to use React's context feature to maintain information about the user throughout the application (e.g. the user ID, which will be used in API calls by various pages). I'm aware that this is an undocumented and not recommended over Redux, but my application is pretty simple (so I don't want or need the complexity of Redux) and this seems like a common and reasonable use case for context. If there are more acceptable solutions for keeping user information globally throughout the application, though, I'm open to using a better method.
However, I'm confused about how it's to be used properly: once the user logins in through the AuthPage (a child of the ContextProvider), how do I update the context in ContextProvider so it can get to other components, like the FridgePage? (Yes, context is technically not supposed to be updated, but this is a one-time operation -- if anyone knows a way to do this when ContextProvider is initialized, that would be more ideal). Does the router get in the way?
I've copied the relevant components here.
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter, Route, Switch } from 'react-router-dom';
import Layout from './components/Layout.jsx';
import AuthPage from './components/AuthPage.jsx';
import ContextProvider from './components/ContextProvider.jsx';
ReactDOM.render(
<ContextProvider>
<HashRouter>
<Switch>
<Route path="/login" component={AuthPage} />
<Route path="/" component={Layout} />
</Switch>
</HashRouter>
</ContextProvider>,
document.getElementById('root')
);
ContextProvider.jsx
import React from 'react';
import PropTypes from 'prop-types';
export default class ContextProvider extends React.Component {
static childContextTypes = {
user: PropTypes.object
}
// called every time the state changes
getChildContext() {
return { user: this.state.user };
}
render() {
return(
<div>
{ this.props.children }
</div>
);
}
}
AuthPage.jsx
import React from 'react';
import PropTypes from 'prop-types';
import AuthForm from './AuthForm.jsx';
import RegisterForm from './RegisterForm.jsx';
import Api from '../api.js';
export default class AuthPage extends React.Component {
static contextTypes = {
user: PropTypes.object
}
constructor(props) {
super(props);
this.updateUserContext = this.updateUserContext.bind(this);
}
updateUserContext(user) {
console.log("Updating user context");
this.context.user = user;
console.log(this.context.user);
}
render() {
return (
<div>
<AuthForm type="Login" onSubmit={Api.login} updateUser={this.updateUserContext} />
<AuthForm type="Register" onSubmit={Api.register} updateUser={this.updateUserContext} />
</div>
);
}
}
Layout.jsx
import React from 'react';
import Header from './Header.jsx';
import { Route, Switch } from 'react-router-dom';
import FridgePage from './FridgePage.jsx';
import StockPage from './StockPage.jsx';
export default class Layout extends React.Component {
render() {
return (
<div>
<Header />
<Switch>
<Route exact path="/stock" component={StockPage} />
<Route exact path="/" component={FridgePage} />
</Switch>
</div>
);
}
}
FridgePage.jsx (where I want to access this.context.user
)
import React from 'react';
import PropTypes from 'prop-types';
import Api from '../api.js';
export default class FridgePage extends React.Component {
static contextTypes = {
user: PropTypes.object
}
constructor(props) {
super(props);
this.state = {
fridge: []
}
}
componentDidMount() {
debugger;
Api.getFridge(this.context.user.id)
.then((fridge) => {
this.setState({ "fridge": fridge });
})
.catch((err) => console.log(err));
}
render() {
return (
<div>
<h1>Fridge</h1>
{ this.state.fridge }
</div>
);
}
}