Skip to content

Latest commit

 

History

History
157 lines (121 loc) · 3.47 KB

Readme.md

File metadata and controls

157 lines (121 loc) · 3.47 KB

Intro

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:

Prerequisites

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 and npm -v in a terminal/console window. Older versions may produce errors.

Steps to build it

  • 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