更新状态后防止顶部滚动

Prevent top scroll after update state

您好,我遇到了问题每次渲染后滚动到首页。 在我的根组件中,当我从 Redux Store 中获取 objects 项数组时。 我在三个 subsArrays 上过滤 mainArray,例如:Hot、Favorite、Regular,然后在特定路线上渲染它们中的每一个。 每次更新mainArray时过滤功能运行:喜欢rating is rise and down or set favorite会被标记。
问题是,为什么每次将动作分派到 redux 存储时都会对渲染做出反应(我想我认为是 redux 造成的)以及我如何防止这种情况发生。 请给我一个提示,我纠结了一段时间...

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

因为您订阅了整个 redux 状态(通过使用 useSelector((state) => state);),请记住每次调度一个动作时,redux 都会计算一个新状态。

所以你不应该写 const state = useSelector(state => state); 否则你的组件将在每次调度动作时重新呈现。相反,您必须 select 您感兴趣的状态部分。

我可以从你的代码中推断出你希望每次 mainList 发生变化时得到通知,所以你可以这样写:

const list = useSelector(state => state.mainList);

您可以通过阅读 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

基本上,您遇到的 scroll to top page 也可能是由于 Route 组件使用不当造成的。

尝试使用这个

<Route path="/regular">
  <MemesView
    list={regularList}
    handleVote={handleVote}
    handleSetFave={handleSetFave}
  />
</Route>

而不是

<Route path="/regular"
       component={() => (
         <MemesView
           list={regularList}
           handleVote={handleVote}
           handleSetFave={handleSetFave}
         />
       )}
/>

别忘了更新 /hot/favorite 路线。

您可以阅读 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).