I have a an App component that renders a CustomerForm
component like so:
App.js
class App extends Component{ constructor(props){ this.state = {logged_in: true}; } logout = () => { this.setState({logged_in: false}): } render(){ return( <div> <CustomerForm /> </div> ) } }
In my CustomerForm
component, I have an onSubmit
function that is called when the form submits:
CustomerForm.js
class CustomerForm extends Component{ constructor(props){ this.state = { submitting: false } } handleSubmit = (e) => { e.preventDefault(); this.setState({submitting: true}); try{ //API CALL HERE }catch(e){ //if error == unauthorized, then logout. } } }
When I render the CustomerForm
component from the App
component, I realize that I could pass a reference to logout
via a prop, however, my application is much larger than the one I have provided here. Ultimately, I want to be able to call the logout()
function that is in the App
component from either like a helper file or any nested component (preferably a helper file). Once this function is called, the state for the App
component would be updated to reflect that the user is now logged out. I tried to use createContext
and this allowed me to pass the attributes and functions I needed, however the functions were only available in the JSX like so:
<authContext.Consumer> {({logout}) => { return ( <Form onSubmit={logout}/> ); }} </authContext.Consumer>
However, I need to be able to access logout
from within the handleSubmit
function. I know that I can pass the logout
function as a reference to handleSubmit, but I figure there is a cleaner way to do this.
Advertisement
Answer
With Context api
and HOC
, you can do that. let me know your thought.
app.js
/ Create a new context for the app export const AppContext = React.createContext('app'); class App extends Component{ constructor(props){ this.state = {logged_in: true}; } logout = () => { this.setState({logged_in: false}): } render(){ return( <AppContext.Provider value={{ state: this.state, logout: this.logout }} > <CustomerForm /> </AppContext.Provider> ) } }
Create a HOC for your Context
withAppContext.js
import {AppContext} from './app.js' export function withAppContext(Component) { return function WrapperComponent(props) { return ( <AppContext.Consumer> {state => <Component {...props} context={state} />} </AppContext.Consumer> ); }; }
CustomerForm.js
import { withAppContext } from 'withAppContext.js' class CustomerForm extends Component{ constructor(props){ this.state = { submitting: false } } handleSubmit = (e) => { this.props.context.logout(); } render() { return ( <> <div>Child</div> <button onClick={this.handleSubmit}>logout</button> </> ); } } export default withAppContext(CustomerForm);