user14249288
user14249288

Reputation:

Add item to end of array, then call function - React

I wasn't sure how to title this correctly. I have an array of items, where I am mapping through them and creating a button for each item. when each button (which represents a category) is clicked, it loads the posts in that category. I am adding an extra item (which will also be a button) to the end of the array that will be a "view all" button, but it will call a different function. So far this component is like:

const Posts = ({ state }) => {
  const [categories, setCategories] = useState([]);
  const [categoryId, setCategoryId] = useState();
  const [page, setPage] = useState(1);
  const [posts, setPosts] = useState([]);

  const [allPosts, setAllPosts] = useState([]);

  useEffect(() => {
    fetch(state.source.api + "/wp/v2/categories")
      .then(response => response.json())
      .then(data => {
        setCategories(data);
      })
  }, []);
  console.log(categories);

  useEffect(() => {
    if (categoryId) {
      fetch(state.source.api + "/wp/v2/posts?categories=" + categoryId + "&per_page=5")
        .then((response) => response.json())
        .then((data) => {
          setPosts(data);
        });
    }
  }, [categoryId]);

  useEffect(() => {
    if (!categoryId) {
      return;
    }
    let url = state.source.api + "/wp/v2/posts?categories=" + categoryId + "&per_page=5";
    if (page > 1) {
      url += `&page=${page}`;
    }
    fetch(url)
      .then((response) => response.json())
      .then((data) => {
        setPosts([...posts, ...data]);
      });
  }, [categoryId, page]);

  useEffect(() => {
    let url = state.source.api + "/wp/v2/posts?per_page=5";
    if (page > 1) {
      url += `&page=${page}`;
    }
    fetch(url)
      .then((response) => response.json())
      .then((data) => {
        setAllPosts([...allPosts, ...data]);
      });
  }, [page]);

  const allCategories = categories.map((category, i) => (category))
  allCategories.push("View All");
  console.log(allCategories);

  return (
    <>
      {allCategories.length > 0 ? (
        allCategories.map((category, i) => {
          return (
            <>
              <button className="btn" key={i} onClick={() => {
                setPage(1);
                setPosts([]);
                setCategoryId(category.id);
              }}>{category.name}</button>
              {(category === "View All") && (<button>View all</button>)}
            </>
          )
        })
      ) : (
          <p>Loading...</p>
        )
      }

      <div>
        {posts.length === 0 ? (
          <>
            {allPosts.map((generalPost, i) => {
              return (
                <li key={i}>{generalPost.title.rendered}</li>
              )
            })}
            <button onClick={() => { setPage(page + 1); }}>Load more</button>
          </>
        ) : (
            <>
              <ol>
                {posts.map((post, i) => {
                  // console.log(post.id);
                  return (
                    <li key={i}>{post.title.rendered}</li>
                  )
                })}
              </ol>

              <button onClick={() => { setPage(page + 1); }}>Load more</button>
            </>
          )}
      </div>
    </>
  )
}

I was able to get the "view all" button to be added to the end, but there seems to be an extra empty button before the "view all" button. I am not sure how that is getting in there. It's displaying like:

[Books] [Movies] [Songs] [ ] [View all]

Is there something wrong with the way I am adding the "view all" button to the array here?

Upvotes: 1

Views: 135

Answers (1)

yqlim
yqlim

Reputation: 7080

In your original code, you are always rendering a <button class="btn">...</button> + conditional check to render <button>View all</button>:

allCategories.map((category, i) => {
  return (
    <>
      <button className="btn" key={i} onClick={() => {
        setPage(1);
        setPosts([]);
        setCategoryId(category.id);
      }}>{category.name}</button>
      {(category === "View All") && (<button>View all</button>)}
    </>
  )
})

Therefore, when category === "View All" is true, it also renders a <button class="btn"> element with empty content because in that case, category.name is undefined.

What you need to do is to make a if-else statement or ternary expression to render only one of them:

allCategories.map((category, i) => {
  return (
    {(category === "View All") ? (
      <button>View all</button>
    ) : (
      <button className="btn" key={i} onClick={() => {
        setPage(1);
        setPosts([]);
        setCategoryId(category.id);
      }}>{category.name}</button>
    )
  )
})

Upvotes: 1

Related Questions