Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HOC's and Render Props With Functional Components in React 16

Tags:

reactjs

I'm somewhat confused on the relationship between functional components in React and the Render Props and HOC patterns.

That is,

is it true that the only way to create Render Prop is with a class component? is it true that the only way to create an HOC is with a class component?

And the same for usage.

I'm trying to find examples of Render Props and HOC's with functional components and all I find are class components. I get that React Hooks do a lot of the same, but I'm trying to understand how the Render Props and HOC patterns can apply to functional components (or if they do at all)


Edit Below:

Applying what @chaimFriedman suggested, this is what I came up with using no class or component for an HOC hoping it makes sense.

import React, { useState, useEffect } from 'react';
import useAxios from 'axios-hooks';

function withFetching(url) {
  return function(Speakers) {
    return () => {
      const [speakerData, setSpeakerData] = useState([]);
      const [isLoading, setIsLoading] = useState(true);
      const [{ data, loading }, refetch] = useAxios('http://localhost:4000/speakers');
      useEffect(() => {
        setSpeakerData(data);
        setIsLoading(loading);
      }, [loading]);

      if (isLoading) return <div>loading..</div>;

      return <Speakers data={speakerData}></Speakers>;
    };
  };
}

const Speakers = function(props) {
  //debugger;
  return (
    <ul>
      {props.data.map((speaker) => (
        <li key={speaker.id}>
          <span>
            {speaker.firstName} {speaker.lastName}
          </span>
        </li>
      ))}
    </ul>
  );
};

const API = 'http://localhost:4000/speakers';
export default withFetching(API)(Speakers);
like image 792
Pete Avatar asked Dec 25 '19 20:12

Pete


People also ask

Can we use render props in functional component?

The term “render prop” refers to a technique for sharing code between React components using a prop whose value is a function. A component with a render prop takes a function that returns a React element and calls it instead of implementing its own render logic.

Can we use render in functional component in React?

It has several advantages, first of all, functional components are just simple javascript functions that accept the information in the form of prop and return the react element, which is HTML content. There is no need to use the render() method inside functional components.

Can functional components have React props?

Function and Class ComponentsThis function is a valid React component because it accepts a single “props” (which stands for properties) object argument with data and returns a React element. We call such components “function components” because they are literally JavaScript functions.


2 Answers

Both render props and HOC can absolutely apply to functional components. Let's think a little more about what each one really is to see why they do in fact work with functions as well as classes.

Render props is when you have a prop that is a function which returns JSX. This of course should work for function components because aside from life cycle methods there really isnt much that is different than class components. Here is an example with code.

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function Renderer(props) {
  return (
    props.children()
  );
}

function App() {
  return (
    <div className="App">
      <Renderer>
        {() => {
          return (
            <h1>I am being rendered by Renderer</h1>
          );
        }}
      </Renderer>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Now for HOC.

A HOC really is just a higher order function, but because we use it in react we call it a higher order component. A higher order function is a function which either accepts a function as an argument, or returns a function. Now a functional component can absolutely do this. Here is an example.

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function Renderer(Wrapped) {
  return function New(props) {
    return <Wrapped {...props} />
  }
}

function Child(props) {
  return (
    <h1>Hello {props.name}</h1>
  );
}

function App() {
  const C = Renderer(Child)
  return (
    <div className="App">
     <C name="john" />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

EDIT: I realized my HOC example was wrong so updated.

I hope this helps.

like image 74
Chaim Friedman Avatar answered Oct 27 '22 19:10

Chaim Friedman


Here is the sample code converting example from React documentation into function component. https://reactjs.org/docs/render-props.html

import React from "react";

const Cat = ({mouse}) => {
  return (
    <img
      src="/cat.png"
      alt="cat"
      style={{ position: "absolute", left: mouse.x, top: mouse.y }}
    />
  );
};

const Mouse = (props) => {
  const [state, setState] = React.useState();

  const handleMouseMove = (event) => {
    setState({
      x: event.clientX,
      y: event.clientY
    });
  };
  
  return (
    <div style={{ height: "100vh" }} onMouseMove={handleMouseMove}>
      {props.render(state)}
    </div>
  );
};

const MouseTracker = () => {
  return (
    <div>
      <h1>Move the mouse around!</h1>
      <Mouse render={(mouse) => <Cat mouse={mouse} />} />
    </div>
  );
};

export const App = () => {
  return (
    <div className="App">
      <MouseTracker />
    </div>
  );
}
like image 40
Si Thu Avatar answered Oct 27 '22 18:10

Si Thu