React Add filtering on pagination - javascript

I have a product page sorted by title. Sorting works, everything is fine, but when pagination occurs, new items are loaded without sorting. How to fix it?
const Grid = ({filter, countOnRow, totalCount, products}) => {
const [fetching, setFetching] = useState(true)
const [total, setTotal] = useState(totalCount)
const [startPage, setStartPage] = useState(0)
const [produs, setProdus] = useState([])
const [okay, setOkay] = useState(false)
const [selectedSort, setSelectedSort] = useState('')
useEffect(()=>{
if(fetching){
setProdus([...produs, ...products.slice(startPage,total)])
setStartPage(total)
setTotal(total+total)
setFetching(false )
}
}, [fetching])
useEffect(()=>{
document.addEventListener('scroll', scrollHadnler);
return function(){
document.removeEventListener('scroll', scrollHadnler)
};
}, [])
const scrollHadnler=(e)=>{
if(e.target.documentElement.scrollHeight-(e.target.documentElement.scrollTop+window.innerHeight)<100){
setFetching(true)
}
}
const sortByName = (sort) => {
setSelectedSort(sort)
setProdus([...produs].sort((a,b) => a[sort].localeCompare(b[sort])))
setOkay(!okay)
}
How can I implement the filtering to persist after pagination.

Related

localStorage.getItem() doesn't retrieve data on page refresh - ReactJs (TypeScript)

I'm trying to create a to-do list app with ReactJs, working with localStorage the setItem() works fine but the getItem() doesn't return anything except empty array!
I'm using || "" because the JSON.parse() returns string || null in TypeScript.
useEffect(() => {
localStorage.setItem("todos", JSON.stringify(todos));
}, [todos]);
useEffect(() => {
const items = JSON.parse(localStorage.getItem("todos") || "");
if (items) {
setTodos(items);
}
}, []);
Here's where i supply data to todos
const [todos, setTodos] = useState<todosObj[]>([]);
const [count, setCount] = useState(1);
const [status, setStatus] = useState<"All" | "completed" | "uncompleted">(
"All"
);
const [inputText, setInputText] = useState("");
const [date, setDate] = useState(new Date());
const inputHandler = (e: React.FormEvent<HTMLInputElement>) => {
setInputText(e.currentTarget.value);
};
const submitHandler = (e: React.FormEvent<HTMLButtonElement>) => {
e.preventDefault();
setCount(count + 1);
if (inputText !== "") {
setTodos([
...todos,
{
id: count,
text: inputText,
completed: false,
date: date,
},
]);
}
setInputText("");
};
Sorry, I dont have enough reputation to comment, so have to post it as an answer:
Is the initial data for todos set? It is better if you can provide where you supply data to todos
I Fixed the problem by initializing the todos state by getItem()
like this :
const [todos, setTodos] = useState<todosObj[]>(
JSON.parse(localStorage.getItem("todos") || "") || []
);
If someone knows the reason why it wasn't working please tell me.
useEffect(() => {
const stringifyTodos = JSON.stringify(todos)
localStorage.setItem("todos", stringifyTodos);
}, [todos]);
useEffect(() => {
const storedTodos = localStorage.getItem("todos")
const items = JSON.parse(storedTodos);
if (items) {
setTodos(items);
}
}, []);
Try this way I think it will work.

useState dosen't work in react - useSelector, useState, useEffect

To load more images, the list should accept the values of images, but it's not working.
Why can't I get the value of the list? (list.length=0 in console)
const { images, imagesLoaded } = useSelector((state: RootState) => state.gallery);
const dispatch = useDispatch();
const [imageUrl, setImageUrl] = useState('');
useEffect(() => {
if(!imagesLoaded) {
dispatch(getImages());
}
// eslint-disable-next-line
}, []);
const [list, setList] = useState([...images.slice(0, 5)])
console.log(images.slice(0, 5))
console.log(list.length)
const [loadMore, setLoadMore] = useState(false)
const [hasMore, setHasMore] = useState(images.length > 5)
const handleLoadMore = () => {
setLoadMore(true)
}
Becasue images only has value after you call dispatch(getImages());
const [list, setList] = useState([...images.slice(0, 5)]) will declare the initial value for list and not update when images update.
if you want update list when images update, you can use useEffect:
useEffect(() => {
setList(images.slice(0, 5))
// eslint-disable-next-line
}, [images]);

How can I fetch and pass the result to the next fetch in react?

How can I fetch the version and languages and pass them to getChampions function
const [version, setVersion] = useState(0)
const [languages, setLanguages] = useState([])
const [selectedLanguage, setSelectedLanguage] = useState('')
const [champions, setChampions] = useState([])
useEffect(() => {
getVersion().then((version) => setVersion(version))
.then(getLanguages().then(languages => {
setLanguages(languages)
setSelectedLanguage(languages[0])
}))
.then(getChampions(version, selectedLanguage).then(champions => setChampions(champions)))
}, [])
I'm getting the default values from the initialization of useState where version = 0 and languages = []
setState is asynchronous, so if you setState and then call a function with the state immediately after you are not guaranteed to get the current state value. #Yadab's answer resolves this but calling getChampions with the variables from the response rather than the variables from the state.
My personal preference is to use a separate hook to respond to changes in the state. It also seems like getVersion and getLanguages don't depend on each other and can be run simultaneously rather than one after the other.
const App = () => {
const [version, setVersion] = useState(0);
const [languages, setLanguages] = useState([]);
const [selectedLanguage, setSelectedLanguage] = useState("");
const [champions, setChampions] = useState([]);
useEffect(() => {
getVersion().then(setVersion);
}, []); // run once - include [setVersion] if using eslint
useEffect(() => {
getLanguages().then((languages) => {
setLanguages(languages);
setSelectedLanguage(languages[0]);
});
}, []); // run once - can include deps [setLanguage, setSelectedLanguage] for eslint
useEffect(() => {
// only execute if both version and selectedLanguage have already been set
if (version && selectedLanguage) {
getChampions(version, selectedLanguage).then(setChampions);
}
}, [version, selectedLanguage]); // run whenever version or selected language changes
...
You can use async await in a separate function to fetch the version and language and use the fetched version and language to fetch the champions data. Take a look at below example.
const [version, setVersion] = useState(0)
const [languages, setLanguages] = useState([])
const [selectedLanguage, setSelectedLanguage] = useState('')
const [champions, setChampions] = useState([])
const fetchData = async () => {
const versionData = await getVersion();
setVersion(versionData)
const languageData = await getLanguages();
setLanguages(languageData)
setSelectedLanguage(languageData[0])
const championsData = await getChampions(versionData, languageData[0])
setChampions(championsData)
}
useEffect(() => {
fetchData();
}, [])

Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. ReactJS

I'm developing a website using ReactJS. And when I run I got "Too many re-renders. React limits the number of renders to prevent an infinite loop." error.
Here is my code:
const [load, setLoad] = useState(false);
const [data, setData] = useState({});
const [server, setServer] = useState({});
const [discord, setDiscord] = useState({});
const [memberCounter, setMemberCounter] = useState(false);
const [emojiCounter, setEmojiCounter] = useState(false);
const [roleCounter, setRoleCounter] = useState(false);
const [boostCounter, setBoostCounter] = useState(false);
const { id, type } = useParams();
useEffect(() => {
fetch('/api/serverinfo/' + id)
.then(res => {
if(res.ok) return res.json();
})
.then(res => {
setLoad(true);
setData(res);
setServer(res._doc);
setDiscord(res.discord);
})
}, []);
if(server.counter && server.counter.length > 0){
server.counter.map(c => {
if(c.type == "members") setMemberCounter(true);
if(c.type == "roles") setRoleCounter(true);
if(c.type == "emojis") setEmojiCounter(true);
if(c.type == "boosts") setBoostCounter(true);
});
}
And it says I have an error on this line
setServer(res._doc);
Any ideas what's the problem?
UPDATE
For those who has this issue, you just need to put setMemberCounter(true);, setRoleCounter(true);, setEmojiCounter(true);, setBoostCounter(true); these inside useEffect().

React Hook's state not getting updated

I've built a React Hook as follows:
const Index = (props) => {
const [posts, setPosts] = useState([])
useEffect(() => {
const getPosts = async () => {
const posts = await getPostFromWebService()
for (let i of posts) {
setPosts([ ...posts, i ])
}
}
getPosts()
}, [])
// ... remaining code
}
But even if the web service returns 5 posts, only the last posts is getting updated in the posts state. Hence it only receives one post in it, instead of 5.
What am I doing wrong here?
It sounds like you want something like this. Here we would have the useEffect listen for any changes in postCount so that we can trigger your logic to fetch more posts.
const Index = (props) => {
const [posts, setPosts] = useState([])
const [postCount, setPostCount] = useState(0)
useEffect(() => {
const getPosts = async () => {
const newPosts= await getPostFromWebService()
setPosts([...posts, newPosts])
}
}, [postCount])
return(
<div>
<button onClick={() => setPostCount(postCount + 5)}>Get more posts</button>
</div>
)
}

Categories

Resources