Skip to content
Advertisement

While creating item from parent to child component, going to infinite loop in React

This is my home page and getting list data then creating List component as much as need. Then going to List component and creating list item. so creating new component using map function. I tried different ways for it but I can’t figure out. It goes infinite loop whatever I did.

Home.jsx

const [lists, setLists] = useState([]);

  useEffect(() => {
    const getRandomList = async () => {
      try {
        const res = await axios.get(`/lists${type ? "?type=" + type : ""}`, {
          headers: {
            "Content-Type": "application/json;charset=UTF-8",
            token: token,
          },
        });
        setLists(res.data);
      } catch (error) {
        console.log(error);
      }
    };
    getRandomList();
  }, [type]);
  return (
    <div className="home">
      <Navbar />
      <Featured type={type} />
      {lists.map((list, index) => {
        return <List key={index} list={list}/>;
      })}
    </div>
  );
}

in List component, creating List item component as much as need.

List.jsx

export default function List({ list }) {
  const [isMoved, setIsMoved] = useState(false);
  const [slideNumber, setSlideNumber] = useState(0);
  const [clickLimit, setClickLimit] = useState(window.innerWidth / 230);
  const [lists, setLists] = useState([])  
  const listRef = useRef();

  useEffect( () =>{
    const getList = ()=>{
      setLists(list.content)
    }
    getList()
  },[list])


  const handleClick = (direction) => {
    setIsMoved(true);
    let distance = listRef.current.getBoundingClientRect().x - 50;
    if (direction === "left" && slideNumber > 0) {
      setSlideNumber(slideNumber - 1);
      listRef.current.style.transform = `translateX(${230 + distance}px)`;
    }
    if (direction === "right" && slideNumber < 10 - clickLimit) {
      setSlideNumber(slideNumber + 1);
      listRef.current.style.transform = `translateX(${-230 + distance}px)`;
    }
  };
  return (
    <div className="list">
      <span className="listTitle">Continue to watch</span>
      <div className="listWrapper">
        <ArrowBackIosOutlined
          className="sliderArrow left"
          onClick={() => handleClick("left")}
          style={{ display: !isMoved && "none" }}
        />
        <div className="listContainer" ref={listRef}>
          {lists.map((item, index) => {
            return <ListItem key={index} index={index} item={item} />;
          })} 
        </div>
        <ArrowForwardIosOutlined
          className="sliderArrow right"
          onClick={() => handleClick("right")}
        />
      </div>
    </div>
  );
}

last component here.

ListItem.jsx

export default function ListItem({ index, item }) {
  const [isHovered, setIsHovered] = useState(false);
  const [movie, setMovie] = useState({});

  useEffect(() => {
    const getMovie = async (item) => {
      try {
        const res = await axios.get("/movies/find/" + item, {
          headers: {
            "Content-Type": "application/json;charset=UTF-8",
            token: token,
          },
        });
        setMovie(res.data);
      } catch (error) {
        console.log(error);
      }
    };  
    getMovie()
    
  }, [item]);

  
  return (
    <div
      className="listItem"
       style={{
        left:
          isHovered &&
          Object.values(index) * 225 - 50 + Object.values(index) * 2.5,
      }}
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)} 
    >
      <img src={movie.img} alt="" />
      {isHovered && (
        <>
          <video src={movie.trailer} autoPlay loop></video>
          <div className="itemInfo">
            <div className="itemIcons">
              <PlayArrow className="itemIcon" />
              <Add className="itemIcon" />
              <ThumbUpAltOutlined className="itemIcon" />
              <ThumbDownAltOutlined className="itemIcon" />
            </div>
            <div className="itemInfoTop">
              <span>1 hour 14 mins</span>
              <span className="limit">{movie.limit}</span>
              <span>{movie.year}</span>
            </div>
            <div className="itemDescription">{movie.description}</div>
            <div className="itemGenre">{movie.genre}</div>
          </div>
        </>
      )}
    </div>
  );
}

Advertisement

Answer

Try to remove the useEffect from the List component and map on the list.content directly:

export default function List({ list }) {
  const [isMoved, setIsMoved] = useState(false);
  const [slideNumber, setSlideNumber] = useState(0);
  const [clickLimit, setClickLimit] = useState(window.innerWidth / 230);

  const listRef = useRef();

  const handleClick = (direction) => {
    setIsMoved(true);
    let distance = listRef.current.getBoundingClientRect().x - 50;
    if (direction === "left" && slideNumber > 0) {
      setSlideNumber(slideNumber - 1);
      listRef.current.style.transform = `translateX(${230 + distance}px)`;
    }
    if (direction === "right" && slideNumber < 10 - clickLimit) {
      setSlideNumber(slideNumber + 1);
      listRef.current.style.transform = `translateX(${-230 + distance}px)`;
    }
  };
  
  return (
    <div className="list">
      <span className="listTitle">Continue to watch</span>
      <div className="listWrapper">
        <ArrowBackIosOutlined
          className="sliderArrow left"
          onClick={() => handleClick("left")}
          style={{ display: !isMoved && "none" }}
        />
        <div className="listContainer" ref={listRef}>
          {list.content.map((item, index) => {
            return <ListItem key={index} index={index} item={item} />;
          })} 
        </div>
        <ArrowForwardIosOutlined
          className="sliderArrow right"
          onClick={() => handleClick("right")}
        />
      </div>
    </div>
  );
}
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement