Search code examples
reactjsreact-hooksuse-effectuse-state

Reactjs, re-render same components, but different return data


A little hard to explain, but please bear with me.

I have this function Component. The function Component code is almost the same, but how can i simplify my function MyComponent with the return value are different to each pages?

Below is my code and to better understand here is the complete sandbox code https://codesandbox.io/.

import { React, useState, useEffect } from "react";

function MyComponent() {
  const [error, setError] = useState(null);
  const [isLoaded, setIsLoaded] = useState(false);
  const [items, setItems] = useState([]);
  useEffect(() => {
    fetch(
      "https://api.unsplash.com/search/photos?query=nature?orientation=landscape&client_id=ddIh7_ebg4KwNHzNLf3ePCZb6yIPREJ5jxG3dYgoj6U"
    )
      .then((res) => res.json())
      .then(
        (result) => {
          setIsLoaded(true);
          setItems(result.results);
        },
        (error) => {
          setIsLoaded(true);
          setError(error);
        }
      );
  }, []);

  if (error) {
    return <div>Error: {error.message}</div>;
  } else if (!isLoaded) {
    return <div>Loading...</div>;
  } else {
    return (
      <div style={{ textAlign: "left" }}>
        This return has to be dynamic. See the function Home and About below.
      </div>
    );
  }
}

export default MyComponent;

Here is my Home and About pages.

function Home() {
  const [items, setItems] = useState([]);
  return (
    <div>
      <h2>Home</h2>
      <ul>
        {items.map((item) => (
          <li key={item.id}>{item.user.last_name}</li>
        ))}
      </ul>
    </div>
  );
}

function About() {
  const [items, setItems] = useState([]);
  return (
    <div>
      <h2>About</h2>
      <ul>
        {items.map((item) => (
          <li key={item.id}>{item.user.first_name}</li>
        ))}
      </ul>
    </div>
  );
}

MyComponent doesn't appear to be rendered in my codesandbox, thats why im asking how can achieve my questions.


Solution

  • The issue is that you've no centralized source of truth. Each of MyComponent, Home, and About each have their own items state. The question you are asking is how to get the items that MyComponent fetched passed to the other two.

    The solution is to Lift State Up. Move all the fetching and rendering logic from MyComponent into App. Pass the items state down to both Home and About.

    App

    export default function App() {
      const [error, setError] = useState(null);
      const [isLoaded, setIsLoaded] = useState(false);
      const [items, setItems] = useState([]);
    
      useEffect(() => {
        fetch(
          "https://api.unsplash.com/search/photos?query=nature?orientation=landscape&client_id=ddIh7_ebg4KwNHzNLf3ePCZb6yIPREJ5jxG3dYgoj6U"
        )
          .then((res) => res.json())
          .then((result) => {
            setItems(result.results);
          })
          .catch((error) => {
            setError(error);
          })
          .finally(() => {
            setIsLoaded(true);
          });
      }, []);
    
      return (
        <BrowserRouter>
          {<Layout />}
          <main>
            {error ? (
              <div>Error: {error.message}</div>
            ) : !isLoaded ? (
              <div>Loading...</div>
            ) : (
              <React.Suspense fallback={<h6>Loading...</h6>}>
                <Routes>
                  <Route path="/" element={<Home items={items} />} />
                  <Route path="/about" element={<About items={items} />} />
                </Routes>
              </React.Suspense>
            )}
          </main>
        </BrowserRouter>
      );
    }
    

    Home

    function Home({ items }) {
      return (
        <div>
          <h2>Home</h2>
          <ul>
            {items.map((item) => (
              <li key={item.id}>{item.user.last_name}</li>
            ))}
          </ul>
        </div>
      );
    }
    

    About

    function About({ items }) {
      return (
        <div>
          <h2>About</h2>
          <ul>
            {items.map((item) => (
              <li key={item.id}>{item.user.first_name}</li>
            ))}
          </ul>
        </div>
      );
    }
    

    Edit reactjs-re-render-same-components-but-different-return-data