In this sample we are going to learn how use render props in React.
In this case we will implement a component that will inject the session to other components via render props.
The main advantage of using this approach instead of HOC is that the child component gets a clear contract of the props it receives.
We will take a startup point sample 18 Hoc:
Install Node.js and npm (v6.6.0) if they are not already installed on your computer.
Verify that you are running at least node v6.x.x and npm 3.x.x by running
node -v
andnpm -v
in a terminal/console window. Older versions may produce errors.
- Let's first add the component that will expose the render prop, we will append it to the sessionContext file.
./src/common/sessionContext.tsx
import * as React from "react"
export interface SessionContextProps {
login: string;
updateLogin: (value) => void;
}
export const createDefaultUser = (): SessionContextProps => ({
login: 'no user',
updateLogin: (value) => { },
});
export const SessionContext = React.createContext<SessionContextProps>(createDefaultUser());
interface State extends SessionContextProps {
}
export class SessionProvider extends React.Component<{}, State> {
constructor(props) {
super(props);
this.state = {
login: createDefaultUser().login,
updateLogin: this.setLoginInfo
}
}
setLoginInfo = (newLogin) => {
this.setState({ login: newLogin })
}
render() {
return (
<SessionContext.Provider value={this.state}>
{this.props.children}
</SessionContext.Provider>
)
};
};
+ interface Props {
+ render : (login : string) => React.ReactNode;
+ }
+
+ export class Session extends React.Component<Props> {
+ constructor(props : Props) {
+ super(props);
+ }
+
+ render() {
+ return (
+ <SessionContext.Consumer>
+ {
+ ({ login, updateLogin }) =>
+ <>
+ {this.props.render(login)}
+ </>
+ }
+ </SessionContext.Consumer>
+ )
+ }
+ }
- Now in the pageB.tsx we can invoke it like that (first approach):
./src/pages/b/pageB.tsx
import * as React from "react"
import { Link } from 'react-router-dom';
import { Session } from '../../common/'
import { checkPropTypes } from "prop-types";
export const PageB = () =>
<div>
<Session
render={
login => (
<>
<h2>Hello from page B</h2>
<br />
<br />
<h3>Login: {login}</h3>
<Link to="/">Navigate to Login</Link>
</>
)}
>
</Session>
</div>
- Let's add one refactor to make the code more readable:
./src/pages/b/pageB.tsx
import * as React from "react"
import { Link } from 'react-router-dom';
import { Session } from '../../common/'
import { checkPropTypes } from "prop-types";
interface Props {
login : string;
}
const PageBComponent = (props: Props) =>
<>
<h2>Hello from page B</h2>
<br />
<br />
<h3>Login: {props.login}</h3>
<Link to="/">Navigate to Login</Link>
</>
export const PageB = () =>
<div>
<Session
render={
login => (
<PageBComponent login={login}></PageBComponent>
)}
>
</Session>
</div>
If you need to nest several render props, you can use react-composer: https://github.com/jamesplease/react-composer