Home > OS >  Avoid render the button after onClick
Avoid render the button after onClick

Time:08-16

I'm trying to render some tags from a source and then put it into a buttons in random form but the issue comes after click the button my component re-render for no reason. why can i do?...

const Blog = () => {
  const [articles, setArticles] = useState([]);
  const [tags, setTags] = useState([]);

  // consult to database
  const getData = async () => {
    try {
      // get aticles, tags
      setArticles([
        { name: "title1", id_tag: 1 },
        { name: "title2", id_tag: 2 }
      ]);
      setTags([
        { id: 1, name: "bell" },
        { id: 2, name: "fashion" }
      ]);
    } catch (e) {
      console.log(e);
    }
  };

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

  const getRandomTag = (i) => {
    const newTags = tags;
    const tag = newTags[Math.floor(Math.random() * newTags.length)];
    return (
      <button key={i} onClick={() => filterByTag(tag.id)}>
        {tag.name}
      </button>
    );
  };

  // filter the article by tag
  const filterByTag = (id) => {
    setArticles(articles.filter((article) => article.id_tag === id));
  };

  return (
    <>
      <ul>
        {articles.map((article, i) => (
          <li key={i}>{article.name}</li>
        ))}
      </ul>
      <h4>TAGS</h4>
      <ul>{tags.map((tag, i) => getRandomTag(i))}</ul>
    </>
  );

export default Blog;

https://codesandbox.io/s/heuristic-solomon-sp640j?from-embed=&file=/src/Blog.js

CodePudding user response:

That's because your component re-renders whenever any state inside it or any props it receives changes either by value or reference. And whenever you map something without caching its value it maps on each rerender. You have tu either split it into other component or use caching.

import { useCallback, useEffect, useMemo, useState } from "react";

const Blog = () => {
  const [articles, setArticles] = useState([]);
  const [tags, setTags] = useState([]);

  // consult to database
  const getData = async () => {
    try {
      // get aticles, tags
      setArticles([
        { name: "title1", id_tag: 1 },
        { name: "title2", id_tag: 2 },
        { name: "title3", id_tag: 3 },
        { name: "title4", id_tag: 4 },
        { name: "title5", id_tag: 5 },
        { name: "title6", id_tag: 6 }
      ]);
      setTags([
        { id: 1, name: "bell" },
        { id: 2, name: "fashion" },
        { id: 3, name: "fancy" },
        { id: 4, name: "tag" },
        { id: 6, name: "name" },
      ]);
    } catch (e) {
      console.log(e);
    }
  };

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

  const filterByTag = useCallback((id) => {
    setArticles(currentArticles => currentArticles.filter((article) => article.id_tag === id));
  }, [setArticles]);

  const getRandomTag = useCallback(
    (i) => {
      const newTags = tags;
      const tag = newTags[Math.floor(Math.random() * newTags.length)];
      return (
        <button key={i} onClick={() => filterByTag(tag.id)}>
          {tag.name}
        </button>
      );
    },
    [tags, filterByTag]
  );

  // filter the article by tag


  const renderTags = useMemo(() => {
    return tags.map((tag, i) => getRandomTag(i));
  }, [tags, getRandomTag]);

  return (
    <>
      <ul>
        {articles.map((article, i) => (
          <li key={i}>{article.name}</li>
        ))}
      </ul>
      <h4>TAGS</h4>
      <ul>{renderTags}</ul>
    </>
  );
};

export default Blog;

Here you have a working example of caching https://codesandbox.io/s/sad-shadow-8pogoc?file=/src/Blog.js

  • Related