Render props pattern

Render props pattern

React render props is a technique used to share code between components, where a component accepts a function as a prop and calls that function to render its output. The function passed as a prop can be used to encapsulate complex logic, state, or functionality and provide it to child components.

Image

Basic Example

To write a render prop, you need to create a component that takes a function as a prop and passes it any necessary data. The function can then use that data to render the desired output. Here’s an example:

import "./styles.css";
import React, { useState } from "react";

const Mouse = ({
  render,
}: {
  render: (position: Position) => React.ReactElement,
}) => {
  const [position, setPosition] = useState < Position > { x: 0, y: 0 };

  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
    setPosition({ x: e.clientX, y: e.clientY });
  };

  return (
    <div className="mouse" onMouseMove={handleMouseMove}>
      {render(position)}
    </div>
  );
};

const App = () => (
  <div className="app">
    <Mouse
      render={(mouse) => (
        <div className="output">
          <h1>
            The mouse position is ({mouse.x}, {mouse.y})
          </h1>
        </div>
      )}
    />
  </div>
);

type Position = {
  x: number,
  y: number,
};

export default App;

As you can see I can change the render prop Inside Mouse component to whatever I like, In this I offer more flexibility on the rendering

Render props and other libraries

It worth to mention that render props is pretty common design pattern between React developers and here are some common libraries that use render props pattern.

For example Formik is one of the most common form libraries that uses render props pattern

import React from 'react';
import { Formik } from 'formik';

const App = () => {
  return (
    <div>
      <Formik
        initialValues={{ email: '', password: '' }}
        onSubmit={(values, actions) => {
          console.log(values);
        }}
      >
        {({ values, handleChange, handleSubmit }) => (
          <form onSubmit={handleSubmit}>
            <input type="email" name="email" onChange={handleChange} value={values.email} />
            <input type="password" name="password" onChange={handleChange} value={values.password} />
            <button type="submit">Submit</button>
          </form>
        )}
      </Formik>
    </div>
  );
};

export default App;

As you can see we render our children as function (like we did on render prop on Mouse component) and get the props from Formik component which contains all the relevant form state and helper methods (such as values, handleChange, handleSubmit). Then render our form elements using these props.

And also MUI supports this pattern by providing slots prop to its DataGrid’s and other components.

<DataGrid
  rows={rows}
  columns={columns}
  slots={{
    columnMenu: MyCustomColumnMenu,
  }}
/>