Search code examples
reactjsasynchronousreact-props

My function as a children is not rendering value from parent component


How come this happens ? I want to update the child component when the state of my parent component changes. But nothing is happening as expected. Can someone please help.

  • in the Fetch, I encapsulate the networking logic : fetch
  • I passed a function as a props with value of data, errors if any and loading state
  • in the callback function I render the data to update my UI

below is one demo with a function as a children following the same pattern of render props.

import { useState, useEffect, useMemo } from "react";
import PropTypes from "prop-types";
import "./App.css";

const Fetch = ({ url, children }) => {
  const [state, setState] = useState({
    loading: false,
    data: null,
    errors: null,
  });

  useEffect(() => {
    setState({ ...state, loading: true });
    fetch(url)
      .then((response) => response.json())
      .then((data) => setState({ ...state, data: data, loading: false }))
      .catch((err) => setState({ ...state, error: err, loading: false }));
  }, [url]);

  const response = useMemo(() => {
    return state;
  }, [state]);

  if (state.loading) return <div>loading ...</div>;
  if (state.errors) return <div>Something went wrong ...</div>;
  if (!state.data) return <div>Sorry, no results</div>;
  return <div>{children({ response })}</div>;
};

Fetch.propTypes = {
  url: PropTypes.string,
};

function List({ Search }) {
  debugger;
  return Search?.map((item) => <Item {...item} />);
}
function Item({ Title }) {
  return <li className="list-group-item">{Title}</li>;
}
function App() {
  return (
    <Fetch url="http://www.omdbapi.com/?s=deadpool&apikey=158fe49">
      {({ data }) => {
        return (
          <div className="list d-flex justify-content-center">
            <ul className="list-group">
              <List {...data} />
            </ul>
          </div>
        );
      }}
    </Fetch>
  );
}

export default App;

debugger - the data is present following the get call debugger - data present in the value passed as argument of the children function debugger - child component not updating with data from parent component

Does anyone know why and how to resolve this ?


Solution

  • The problem is in the Fetch component. You probably meant return <div>{children(response)}</div>, because return <div>{children({ response })}</div> will call the render function with an object that has a key response.

    Additionally, when this is fixed, the List component throws an error because Search?.map((item) => <Item {...item} />) will return undefined if Search is falsy, which is not acceptable. Instead, you should return null or false.

    function List({ Search }) {
      return Search ? Search.map((item) => <Item {...item} />) : null;
    }