felipeab
felipeab

Reputation: 110

Quick explanation of state management with react hooks

I just started using react hooks and I have a quick question. Can I just declare const [page] = useState(1); instead of const [page, setPage] = useState(1); and not call setPage at all? the reason I ask is because I see that by using setPage I cause an unnecessary render of the page with the current code. Please take a look, you can also see a working sample and modify here: https://uqdil.csb.app/

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

export default function App() {
  const [userData, setUserData] = useState([]);
  const [page, setPage] = useState(1);

  const getUserData = async (page) => {
    try {
      const url = `https://randomuser.me/api?page=${page}`;
      const response = await axios.get(url);
      setUserData([...userData, ...response.data.results]);
    } catch (error) {
      console.log("error >> ", error);
    }
  };

  const getUser = (page = 1) => {
    setPage(page);
    getUserData(page);
  };

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

  const getUserName = (user) => {
    const {
      name: { first, last }
    } = user;
    return `${first} ${last}`;
  };

  const getImagUrl = (user) => {
    const {
      picture: { large }
    } = user;
    return `${large}`;
  };

  if (!userData) {
    return <p>Loading user data ... </p>;
  }
  return (
    <div className="App">
      {userData.map((user, idx) => {
        const userName = getUserName(user);
        return (
          <div key={idx} style={{ marginTop: "20px" }}>
            <img alt={userName} src={getImagUrl(user)} />
            <p>User Name: {userName}</p>
          </div>
        );
      })}
      <button
        onClick={() => {
          getUser(page + 1);
        }}
      >
        Load More
      </button>
    </div>
  );
}

Upvotes: 0

Views: 56

Answers (2)

Alen.Toma
Alen.Toma

Reputation: 4870

Yes you can, if you do not want to change the page. Now that is not the problem you are having. as long as that you do not include page in your HTML, nothing will re render when you setPage You could also include var page on top of function App and modify it as you like without trigging an update.

But in this case it will be pointless.

See below how you could modify your code.

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

export default function App() {
  const [userData, setUserData] = useState([]);
  const [page, setPage] = useState(1);

  const getUserData = async() => {
    try {
      const url = `https://randomuser.me/api?page=${page}`;
      const response = await axios.get(url);
      setUserData([...userData, ...response.data.results]);
    } catch (error) {
      console.log("error >> ", error);
    }
  };

  const nextPage = () => {
    setPage(page + 1);
  }

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

  useEffect(() => {
    getUserData(); // when page is changed then get users
  }, [page]);

  const getUserName = (user) => {
    const {
      name: {
        first,
        last
      }
    } = user;
    return `${first} ${last}`;
  };

  const getImagUrl = (user) => {
    const {
      picture: {
        large
      }
    } = user;
    return `${large}`;
  };

  if (!userData) {
    return <p > Loading user data... < /p>;
  }
  return ( <
    div className = "App" > {
      userData.map((user, idx) => {
        const userName = getUserName(user);
        return (<div key = {
            idx
          }
          style = {
            {
              marginTop: "20px"
            }
          }>
          <img alt = {
            userName
          }
          src = {
            getImagUrl(user)
          }/> 
          <p> User Name: {
            userName
          } </p> 
          </div>
        );
      })
    } 
    <button onClick={nextPage}>
    Load More 
    </button> 
    </div>
  );
}

Upvotes: 1

Nicholas Tower
Nicholas Tower

Reputation: 85241

Can I just declare const [page] = useState(1); instead of const [page, setPage] = useState(1); and not call setPage at all?

If you don't want to change the state, then yes, you can just destructure element 0 of the array. That's pretty rare though, since usually the reason for having a state variable is that you want it to be able to change.

About the only reason i can think of to create a state that will never change is that you have some value which is changing beyond your control, and you want to remember what the value was on the first render. Since useState's default value is only used on the first render, useState kinda lets you do that:

const Example = ({ propThatMayChange }) => {
  const [initialValue] = useState(propThatMayChange);

  // ...
}

The same can also be achieved with a ref, though since it's a mutable object someone might in principle change it:

const Example = ({ propThatMayChange }) => {
  const initialValueRef = useRef(propThatMayChange);

  // ...
}

Upvotes: 1

Related Questions