DEV Community

Sidharth Juyal
Sidharth Juyal

Posted on • Originally published at whackylabs.com on

React navigation basics

I just realized that I’ve never made the photos app with react.js. So let’s do that today.

React vs React Native

Setup

I’m going to use vite to build the app with javascript.

npm create vite@latest .
npm install
npm run dev

Enter fullscreen mode Exit fullscreen mode

And we have our app up and running.

setup

Fetch data

To fetch and display data in react is a three step process. First we need useState to hold the data:

const [photoList, setPhotoList] = useState([]);

Enter fullscreen mode Exit fullscreen mode

Then we need a useEffect to fetch the data. One way is to use the promises:

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/photos")
      .then((response) => response.json())
      .then((content) => setPhotoList(content));
  }, []);

Enter fullscreen mode Exit fullscreen mode

Another way is to create an async function and call it from useEffect:

  async function fetchData() {
    const response = await fetch("https://jsonplaceholder.typicode.com/photos");
    const content = await response.json();
    setPhotoList(content);
  }

  useEffect(() => {
    fetchData();
  }, []);

Enter fullscreen mode Exit fullscreen mode

And then draw the UI.

Drawing content

To render the data we can simply use the html unordered list

return (
  <>
    {photoList.length === 0 ? (
      <p>Loading ...</p>
    ) : (
      <ul>
        {photoList.map(({ id, title, thumbnailUrl }) => {
          return (
            <li key={id}>
                <img src={thumbnailUrl} alt={title} />
            </li>
          );
        })}
      </ul>
    )}
  </>
);

Enter fullscreen mode Exit fullscreen mode

photo-list

In the true spirit of react we can probably move the li out as a reusable component and call it PhotoTile:

export function PhotoTile({ title, thumbnailUrl }) {
  return (
    <li className="photoTile">
      <img src={thumbnailUrl} alt={title} />
    </li>
  );
}

Enter fullscreen mode Exit fullscreen mode

and reduce our App.jsx to

<ul className="photoList">
  {photoList.map(({ id, title, thumbnailUrl }) => (
    <PhotoTile key={id} title={title} thumbnailUrl={thumbnailUrl} />
  ))}
</ul>

Enter fullscreen mode Exit fullscreen mode

Next, to make the list 2 columns we can use grid, flexbox or one of the infinite other methods out there, but my favorite is to simply use the column-count

<ul className="photoList"> 
  ...
</ul>

.photoList {
  column-count: 2;
}

Enter fullscreen mode Exit fullscreen mode

two-columns

Navigation

And now the real deal. The react-router-dom. This changes everything. First we need to install the dependency obviously.

npm install react-router-dom

Enter fullscreen mode Exit fullscreen mode

Then we need to update the main.jsx to use the router

const router = createBrowserRouter([
  {
    path: "/",
    element: <Home />,
  },
]);

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <RouterProvider router={router} />
  </StrictMode>
);

Enter fullscreen mode Exit fullscreen mode

To navigate to the details, we need to register the route with params:

const router = createBrowserRouter([
  {
    path: "/",
    element: <Home />,
  },
  {
    path: "/details/:id",
    element: <Details />,
  },
]);

Enter fullscreen mode Exit fullscreen mode

Then in the Details we can get the param value with useParams() hook

export function Details() {
  const { id } = useParams();
  const [photo, setPhoto] = useState(null);

  async function fetchData(id) {
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/photos/${id}`
    );
    const content = await response.json();
    setPhoto(content);
  }

  useEffect(() => {
    fetchData(id);
  }, [id]);

  return (
    <>
      {!photo ? (
        <Loading />
      ) : (
        <ul>
          <div className="photoDetails">
            <PhotoTile title={photo.title} url={photo.url} />
            <p>{photo.title}</p>
          </div>
        </ul>
      )}
    </>
  );
}

Enter fullscreen mode Exit fullscreen mode

two-columns

And then to navigate between screens we need to make use of the Link component:

export function PhotoTile({ title, url, path }) {
  return (
    <li className="photoTile">
      <Link to={path}>
        <img src={url} alt={title} />
      </Link>
    </li>
  );
}

Enter fullscreen mode Exit fullscreen mode

And then construct the details path from Home screen like:

<PhotoTile
  key={id}
  title={title}
  url={thumbnailUrl}
  path={`/details/${id}`}
/>

Enter fullscreen mode Exit fullscreen mode

And back to home from the Details screen:

<PhotoTile title={photo.title} url={photo.url} path={"/"} />

Enter fullscreen mode Exit fullscreen mode

Conclusion

And there we have the basics of a React app with navigation. The react-router is always evolving, there were some new changes in the v6 which I tried to use. But looks good and works like charm.

The link from this experiment is available at https://github.com/chunkyguy/PhotoApp/tree/master/react.

References

Top comments (0)