A React utility function to decorate a component with context, similar to how react-redux works.
You might want to look into upcoming experimental useContext
React Hook which might solve the problem in much more elegant way.
npm install @swiggy/react-context-decorator
While render props pattern is a cool way to get data out
from a Component, it can be quite messy to use. Higher Order Components tend to keep code less messy, but have their own issues. However, we feel that it would've been a nightmare if Redux never shipped with connect
(part of react-redux) and asked the user to rely on Render props everywhere. Similar to connect
, decorateWithContext
makes it easier to mapContextToProps
and escape from render prop hell.
View on CodeSandbox.
import React from "react";
import ReactDOM from "react-dom";
import { decorateWithContext } from "@swiggy/react-context-decorator";
/*
This is how our component heirarchy is
<App /> (has the context value)
|
|_<Content />
|
|_<Profile />
|
|_<MyGreeting />
| |
| |_<Greeting /> (context.name -> props.name)
|
|_<MyAge />
|
|_<Age /> (context.age -> props.age)
Instead of passing props from App -> Content -> Profile -> Greeting,
we would make use of React's context API to directly pass it from App to Greeting.
*/
// Create context using new Context API
const MyContext = React.createContext({ name: "", age: 0 });
// Decorate with `MyContext`
const withMyContext = decorateWithContext(MyContext);
// Your Component that would receive context value in props
const Greeting = props => <h1>Hello {props.name}!</h1>;
// Pick `name` from the context
const withName = withMyContext(context => ({ name: context.name }));
// Decorated component
const MyGreeting = withName(Greeting);
// Your Component that would receive context value in props
const Age = props => <p>Your age is {props.age}.</p>;
// Pick `age` from the context
const withAge = withMyContext(context => ({ age: context.age }));
// Decorated component
const MyAge = withAge(Age);
const Profile = props => (
<React.Fragment>
<MyGreeting />
<MyAge />
</React.Fragment>
);
const Content = props => (
<div>
<Profile />
</div>
);
class App extends React.PureComponent {
state = {
age: 0,
name: ""
};
render() {
return (
<MyContext.Provider value={this.state}>
<input
type="text"
placeholder="Enter your name"
value={this.state.value}
onChange={e => this.setState({ name: e.target.value })}
/>
<input
type="number"
placeholder="Enter your age"
value={this.state.age}
onChange={e => this.setState({ age: e.target.value })}
/>
<Content />
</MyContext.Provider>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Feel free to report issues or raise pull requests.