I'm working with react-infinite-scroll-component
library and randomuser.me api. I can fetch the data and the infinite scroll works just fine but the problem I have is that since the component makes a request at every scroll, I'm getting repeatable results.
I've found a workaround that removes arrays that are the same but it is not working properly with the infinite scroll package.
This is my code:
function App() {
const [people, setPeople] = useState([]);
const fetchPeopleImages = () => {
axios.get(`https://randomuser.me/api/?results=30&nat=br`).then((res) => {
const result = res.data.results;
setPeople([...people, ...result]);
});
// if (people.length > 30) {
// const removedDuplicatedPeople = people.filter(
// (ele, ind) =>
// ind ===
// people.findIndex(
// (elem) => elem.picture.medium === ele.picture.medium,
// ),
// );
// setPeople([...people, removedDuplicatedPeople]);
// }
};
useEffect(() => {
fetchPeopleImages();
// commented below because ESLINT was asking me to use useCallback
// inside fetchPeopleImage func. idk why
// eslint-disable-next-line
}, []);
return (
<div className="App">
<InfiniteScroll
dataLength={people.length}
next={() => fetchPeopleImages()}
hasMore={true}
loader={<h4>Carregando...</h4>}
endMessage={
<p style={{ textAlign: 'center' }}>
<b>Yay! You have seen it all</b>
</p>
}
>
{people.length > 1 &&
people.map((people, i) => (
<div>
<img src={people.picture.medium} alt="Imagem de uma pessoa" />
</div>
))}
</InfiniteScroll>
</div>
);
}
export default App;
What is commented was the workaround I've found to remove arrays that have the same image link. Codesandbox: https://codesandbox.io/s/gracious-wildflower-opjx5?file=/src/App.js
Ideally don't do the filtering business specially with frequent fetches (like scroll). It is better if you maintain a state say page
and pass it to your api and the api should return the data.
The problem with the inconsistency you are facing is due to the limitations of randomuser.me api. The api has only limited images to serve, so it will mix up the names, ages, images etc and tries its best to serve unique records. Hence you will often see duplicate images. You can check by rendering the name along with image and you will see 2 same images will have different names.
Some suggestions to solve your issue:
- provide a low value to results
query param say 10
- use seed
option to the api
- on every scroll increment the page
and pass it to the api query param
See updated demo here - it works to some extent
Note - you are still not guaranteed to see unique images rendered. However, you can use the updated code and it will work when you use it with real api.
updated code snippet
function App() {
const [people, setPeople] = useState([]);
const [page, setPage] = useState(0);
const fetchPeopleImages = () => {
axios
.get(`https://randomuser.me/api/?results=10&nat=br&page=${page}&seed=abc`)
.then(res => {
const result = res.data.results;
setPeople([...people, ...result]);
setPage(prev => prev + 1);
});
console.log("page", page);
};
useEffect(() => {
fetchPeopleImages();
// commented below because ESLINT was asking me to use useCallback inside
// fetchPeopleImage func. idk why
// eslint-disable-next-line
}, []);
return (
<div className="App">
<InfiniteScroll
dataLength={people.length}
next={() => fetchPeopleImages()}
hasMore={true}
loader={<h4>Loading.....</h4>}
endMessage={
<p style={{ textAlign: "center" }}>
<b>Yay! You have seen it all</b>
</p>
}
>
{people.length > 1 &&
people.map((people, i) => (
<div key={i}>
<img src={people.picture.medium} alt="Person" />
<p>{people.name.first}</p>
</div>
))}
</InfiniteScroll>
</div>
);
}