skip to Main Content

i have a "carousel" displaying fruits,
also has a like button beside the carousel,

im loading carousel items with fruits (arr of objects) which is a response of a GET req,
i used "loader" from react-router for this GET req,
fruits here is a list of fruits a user has,
different users have different "isLiked" properties

const response = useLoaderData()
const fruits = response.data;

fruits looks like this,

[
  {
    id: 1,
    name: 'apple',
    isLiked: true,
  },
  {
    id: 2,
    name: 'orange',
    isLiked: false
  },
  {
    id: 3,
    name: 'pineapple',
    isLiked: true
  },
];

this is my component,

const Fruits = () => {
  
  const [fruitIndex, setFruitIndex] = useState(0);
  const [currentFruit, setCurrentFruit] = useState(fruits[fruitIndex]);
  const isThisFruitLiked = currentFruit.isLiked;

  const handlePreviousFruit = () => {
    if (fruitIndex === 0) {
      let lastFruitIndex = fruits.length - 1;
      setFruitIndex(lastFruitIndex);
      setCurrentFruit(fruits[lastFruitIndex]);
    } else {
      setFruitIndex((prev: any) => prev - 1);
      setCurrentFruit(fruits[fruitIndex - 1]);
    }
  };

  const handleNextFruit = () => {
    if (fruitIndex >= fruits.length - 1) {
      setFruitIndex(0);
      setCurrentFruit(fruits[0]);
    } else {
      setFruitIndex((prev: any) => prev + 1);
      setCurrentFruit(fruits[fruitIndex + 1]);
    }
  };

  const handleLike = async (id, isLiked) => {
    try {
      const reqBody = {
        id,
        isLiked,
      };

      if (isLiked) { // like a fruit
        const response = await axios.post(`/api/v1/fruits`, reqBody);
        const statusIsOk = response.status === 200;
        if (statusIsOk) {
          // change no to yes in "p tag"
        }
      } else { // un-like a fruit
        const response = await axios.delete(`/api/v1/fruits?id=${id}`);
        const statusIsOk = response.status === 200;
        if (statusIsOk) {
          // change yes to no in "p tag"
        }
      }
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <>
      <div>
        <p>
          {' '}
          {`Do i like ${currentFruit.name}? ${
            currentFruit.isLiked ? 'yes' : 'no'
          }`}
        </p>
        <button
          onClick={() => {
            /* like or un-like a fruit */
            if (isThisFruitLiked) {
              handleLike(currentFruit.id, false);
            } else {
              handleLike(currentFruit.id, true);
            }
          }}
        >
          like button
        </button>
      </div>

      <br />
      <br />

      <button onClick={handlePreviousFruit}>previous</button>
      <button onClick={handleNextFruit}>next</button>
    </>
  );
};

i want my component to re-render everytime i like/un-like the fruit,
with my implementation, i need to restart the page for the component to update.

2

Answers


  1. Well currently you are not setting the state in your handleLike function, and because of that your page is not rerendering.

    Login or Signup to reply.
  2. For this to work, you need to have your fruits as state.

    const [fruits, setFruits] = useState();
    const response = useLoaderData();
    
    useEffect(()=>{
        const fruits = response.data;
    },[response]);
    

    Now you can update the liked field of fruits and call setFruits(…fruits).

    However, you just want to force update keeping the current set up, you can use a dummy state to force an update.

    const [_, forceUpdate] = useState({});
    
    // when you need to force re-render
    forceUpdate({});
    

    This works because each object is different.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search