Hi I have problem with scroll to top page after every render.
In my Root component, when I get Array of objects items from Redux Store.
I filter mainArray on three subsArrays like : Hot, Favorite, Regular, then render each of them on specific route.
The filter func is running each time when mainArray is updated: like rating is rise and down or set favorite will be marked.
The question is, why react render each times when action is dispatching to redux store(I think redux causes this,I guess) and how I can prevent this.
Please give me a hint, I struggle with it for a while...
function Root() {
const state = useSelector((state) => state);
const { mainList: list } = state;
const [regularList, setRegularList] = useState([]);
const [hotList, setHotList] = useState([]);
const [favoriteList, setFavoriteList] = useState([]);
const dispatch = useDispatch();
const handleVote = (e) => {
const currentId = Number(e.nativeEvent.path[3].id);
const name = e.currentTarget.dataset.name;
dispatch(listActions.vote(currentId, name));
};
const handleSetFave = (e) => {
const currentId = Number(e.nativeEvent.path[3].id);
dispatch(listActions.setFave(currentId));
const setArrays = (arr) => {
const regularArr = arr.filter((meme) => meme.upvote - meme.downvote <= 5);
const hotArr = arr.filter((meme) => meme.upvote - meme.downvote > 5);
const favoriteArr = arr.filter((meme) => meme.favorite);
setRegularList([...regularArr]);
setHotList([...hotArr]);
setFavoriteList([...favoriteArr]);
};
useEffect(() => {
window.localStorage.getItem("mainList") &&
dispatch(
listActions.setMainList(
JSON.parse(window.localStorage.getItem("mainList"))
)
);
}, []);
useEffect(() => {
setArrays(list);
list.length > 0 &&
window.localStorage.setItem("mainList", JSON.stringify(list));
}, [list]);
return (
<div className={styles.App}>
<Router>
<Navigation />
<Route path="/" component={FormView} exact />
<Route
path="/regular"
component={() => (
<MemesView
list={regularList}
handleVote={handleVote}
handleSetFave={handleSetFave}
/>
)}
/>
<Route
path="/hot"
component={() => (
<MemesView
list={hotList}
handleVote={handleVote}
handleSetFave={handleSetFave}
/>
)}
/>
<Route
path="/favorite"
component={() => (
<MemesView
list={favoriteList}
handleVote={handleVote}
handleSetFave={handleSetFave}
/>
)}
/>
</Router>
</div>
);
};
why react render each times when action is dispatching to redux store
Because you are subscribing to the whole redux state (by using useSelector((state) => state);), remember that each time an action is dispatched, redux computes a new state.
So you should not write const state = useSelector(state => state); otherwise your component will be rerendered each time an action is dispatched. Instead you must select the part of the state you are interested in.
I can deduce from your code you want to be notified every time there is a change on the mainList, so you can write :
const list = useSelector(state => state.mainList);
You can get more info by reading the documentation
by default useSelector() will do a reference equality comparison of the selected value when running the selector function after an action is dispatched, and will only cause the component to re-render if the selected value changed
Basically, the scroll to top page you are experiencing might also comes from a bad use of the Route component.
Try to use this
<Route path="/regular">
<MemesView
list={regularList}
handleVote={handleVote}
handleSetFave={handleSetFave}
/>
</Route>
instead of
<Route path="/regular"
component={() => (
<MemesView
list={regularList}
handleVote={handleVote}
handleSetFave={handleSetFave}
/>
)}
/>
Don't forget to also update /hot and /favorite routes.
You can read from the react router documentation
When you use component (instead of render or children, below) the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function to the component prop, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component. When using an inline function for inline rendering, use the render or the children prop (below).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With