Skip to content

Problem with conditional statements in React Hook

I wrote a program that takes a data that has an object from the movie and adds the state of the watch to each of the objects and puts it in the state. The whole program works properly My only problem is that when I click on the watched button, I want the text of the button to be changed to not watched and to be included in the watched list. At the top, I have two buttons, watched and not watched, which one I clicked on. Show me the list of the movies that I changed, their state In fact, every time I click on the button, I want the state of Watched in the object of that movie to change to false and click again to true. I specified in the code with a comment I know my questions are a bit confusing, but thank you for helping me

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

    const App = () => {
      const [getMovies, setMovie] = useState([]);
      const [getLoading, setLoading] = useState(true);
      const [getKeyword, setKeyword] = useState("");
      const [getOverSeven, setOverSeven] = useState(false);
      const [getWatched, setWatched] = useState(true);
      const [getNotWatched, setNotWatched] = useState(false);
      const [getTextBtn, setTextBtn] = useState(false);

      useEffect(() => {
        fetch("http://my-json-server.typicode.com/bemaxima/fake-api/movies")
          .then((response) => response.json())
          .then((response) => {
            setMovie(
              response.map((item) => ({
                id: item.id,
                name: item.name,
                rate: item.rate,
                watched: false,
              }))
            );
            setLoading(false);
          });
      }, []);
//This is the part that I want every time I click on the button of each movie
// to change the button to not watched and in the state of watching state
// to false and with the next click to become true
      function handleWatchedBtn(id) {
        setTextBtn(!getTextBtn);
        const index = getMovies.findIndex((p) => p.id === id);
        if (index) {
          if (getTextBtn === true) {
            setMovie({
              id,
              name,
              rate,
              watched: true,
            });
          } else {
            setMovie({
              id,
              name,
              rate,
              watched: false,
            });
          }
        }
      }
      function handleKeywordChange(e) {
        setKeyword(e.target.value);
      }
      function handleOverSevenChange(e) {
        setOverSeven(e.target.checked);
      }
      function handleShow() {
        setNotWatched(!getNotWatched);
        setWatched(!getWatched);
      }
      function filterItems(getKeyword, getOverSeven, getWatched, getNotWatched) {
        const arr = getMovies.map((item) => ({
          id: item.id,
          text: item.name,
          rate: item.rate,
          watched: item.watched,
        }));
        return arr
          .filter((item) =>
            item.text.toLowerCase().includes(getKeyword.toLowerCase())
          )
          .filter((item) => (getOverSeven ? item.rate > 7 : true))
          .filter((item) => (getWatched ? item.watched === true : getNotWatched))
          .filter((item) => (getNotWatched ? item.watched === false : getWatched));
      }
      const result = filterItems(
        getKeyword,
        getOverSeven,
        getNotWatched,
        getWatched
      );
      if (getLoading) {
        return "Please wait...";
      }
      return (
        <div>
          <div>
            <div>
              Keyword
              <input
                type="text"
                value={getKeyword}
                onChange={handleKeywordChange}
              />
            </div>
            <div>
              <button onClick={handleShow}>watch</button>
              <button onClick={handleShow}>not watch</button>
            </div>
            <div>
              Only over 7.0
              <input
                type="checkbox"
                checked={getOverSeven}
                onChange={handleOverSevenChange}
              />
            </div>
            <div>
              <ul>
                {result.map((item) => (
                  <li data-id={item.id}>
                    {`${item.id} : ${item.text} ${item.rate}`}{" "}
                    <button onClick={handleWatchedBtn}>
                      {getTextBtn ? "Not watched" : " Watched"}
                    </button>
                  </li>
                ))}
              </ul>
            </div>
          </div>
        </div>
      );
    };
    export default App;

Answer

Your state has too many useState state objects. It’s better to move them all to a single state.

Next the problem with watched and not watched buttons not working is that you are not passing your movie id to handleShow function.

Also having two different booleans like getWatched and getNotWached to filter your movie list is not necessary and adds extra complexity.So move it to a single variable like filterByWatch which can be "ALL" | "WATCHED" | "NOT_WATCHED". So you just have to change one variable while toggling -> fewer state updates

handleWatchedBtn function also needs some change. You extracted the index of the movie that is clicked to toggle but you are not using that later in the function.

Here is an attempt to fix all the above-mentioned issues.

Please feel free to comment with any questions you have about the below code.

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

    const initialState = {
      movies: [],
      loading: true,
      searchKeyword: "",
      filterOverSeven: false,
      filterByWatch: "ALL" // Can be "ALL" | "WATCHED" | "NOT_WATCHED"
    };

    const App = () => {
      const [state, setState] = useState(initialState);

      useEffect(() => {
        fetch("https://my-json-server.typicode.com/bemaxima/fake-api/movies")
          .then((response) => response.json())
          .then((response) => {
            setState((s) => ({
              ...s,
              movies: response.map((item) => ({
                id: item.id,
                name: item.name,
                rate: item.rate,
                watched: false
              })),
              loading: false
            }));
          });
      }, []);

      function handleWatchedBtn(id) {
        setState((s) => ({
          ...s,
          movies: s.movies.map((movie) => {
            if (movie.id === id) {
              return { ...movie, watched: !movie.watched };
            }
            return movie;
          })
        }));
      }

      function handleKeywordChange(e) {
        setState((s) => ({ ...s, searchKeyword: e.target.value }));
      }

      function handleOverSevenChange(e) {
        setState((s) => ({ ...s, filterOverSeven: !s.filterOverSeven }));
      }

      function handleWatchedChange(filter) {
        setState((s) => ({ ...s, filterByWatch: filter }));
      }

      function filterItems() {
        return state.movies
          .filter((item) =>
            item.name.toLowerCase().includes(state.searchKeyword.toLowerCase())
          )
          .filter((item) => (state.filterOverSeven ? item.rate > 7 : true))
          .filter((item) =>
            state.filterByWatch === "ALL"
              ? true
              : item.watched === (state.filterByWatch === "WATCHED")
          );
      }

      if (state.loading) {
        return "Please wait...";
      }

      return (
        <div>
          <div>
            <div>
              Keyword
              <input
                type="text"
                value={state.searchKeyword}
                onChange={handleKeywordChange}
              />
            </div>
            <div>
              <button onClick={() => handleWatchedChange("ALL")}>all</button>
              <button onClick={() => handleWatchedChange("WATCHED")}>watch</button>
              <button onClick={() => handleWatchedChange("NOT_WATCHED")}>
                not watch
              </button>
            </div>
            <div>
              Only over 7.0
              <input
                type="checkbox"
                checked={state.filterOverSeven}
                onChange={handleOverSevenChange}
              />
            </div>
            <div>
              <ul>
                {filterItems().map((movie) => (
                  <li data-id={movie.id}>
                    {`${movie.id} : ${movie.name} ${movie.rate}`}{" "}
                    <button onClick={() => handleWatchedBtn(movie.id)}>
                      {movie.watched ? "Watched" : " Not watched"}
                    </button>
                  </li>
                ))}
              </ul>
            </div>
          </div>
        </div>
      );
    };

    export default App;