You should only have to care about the index of the item when it comes to checking the state.
<EachHeart
checked={heartsClicked[index]}
onClick={handleClick}
index={index}
/>
const handleClick = (index) => {
setHeartsClicked((existing) => {
const copy = [...existing];
copy[index] = !copy[index];
return copy;
});
};
Also, these states are pointless:
const [isLike, setIsLike] = useState(false);
const [heartIndexClicked, setHeartIndexClicked] = useState();
Working example
Try the following:
Note: I changed first10
to visibleData
. It's a better name that I already suggested yesterday. I also changed the size from 10 to 15. You should use a variable instead of hard-coding magic numbers.
import { useCallback, useMemo, useState } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
import { TbHeart } from "react-icons/tb";
import { arr } from "./utils";
export function EachHeart({ checked, index, onClick }) {
return (
<>
<TbHeart
key={index}
onClick={() => onClick(index)}
className={` mt-9 ${
checked &&
"fill-green-500 transition-colors ease-in delay-150 hover:scale-[1.20]"
} stroke-green-500 ml-5 w-5 h-5 cursor-pointer`}
/>
</>
);
}
const pageSize = 15;
export default function App() {
const [visibleData, setVisibleData] = useState(arr.slice(0, pageSize));
const [page, setPage] = useState(1);
const [heartsClicked, setHeartsClicked] = useState([]);
const fetchMoreData = useCallback(() => {
setTimeout(() => {
setVisibleData((prev) => [
...prev,
...arr.slice(page * pageSize, page * pageSize + pageSize),
]);
setPage((prev) => (prev += 1));
}, 2000);
}, []);
const handleClick = useCallback((index) => {
setHeartsClicked((existing) => {
const copy = [...existing];
copy[index] = !copy[index]; // Invert true/false
return copy;
});
}, []);
const isDone = useMemo(() => visibleData.length < arr.length, [visibleData]);
return (
<>
<div className="mt-24"></div>
<InfiniteScroll
dataLength={visibleData.length}
next={fetchMoreData}
hasMore={isDone}
loader={<h3 className="font-bold text-center text-xl">Loading...</h3>}
endMessage={
<p className="text-base my-4 font-medium text-center">
<b>Yay! You have seen it all</b>
</p>
}
>
{visibleData.map((t, index) => {
return (
<>
<div className="flex ">
<li key={index} className="mx-4 mt-8">
{t.name.concat(` ${t.id}`)}
</li>
<EachHeart
checked={heartsClicked[index]}
onClick={handleClick}
index={index}
/>
</div>
</>
);
})}
</InfiniteScroll>
</>
);
}