为了账号安全,请及时绑定邮箱和手机立即绑定

如何防止重新选择重新渲染?

如何防止重新选择重新渲染?

森林海 2022-05-22 11:14:09
我今天正在尝试reselect中间件并防止不必要的重新渲染。这是我的 reducer.js:const INITIAL_STATE = {  dogs: 100,  cats: 12312302384};const pets = (state = INITIAL_STATE, action) => {  switch (action.type) {    case "CHANGE_DOGS":      return {        ...state, dogs: state.dogs + 1      };    case "CHANGE_CATS":      return {        ...state, cats: state.cats + 1      };    default:      return { ...state };  }};export default pets;这是我的 main.js:import React from "react";import { createSelector } from "reselect";import { useSelector, useDispatch } from "react-redux";function ReduxDeneme(props) {  // Selectors - Classic style - NON Memoized!//   const dogsData = useSelector(state => state.pets.dogs);//   const catsData = useSelector(state => state.pets.cats);  //                          Dogs rendering..  --> First opening..  // 10:11:28.070 index.js:18 CATS rendering.. --> First opening..  // 10:11:29.703 index.js:13 Dogs rendering.. --> Press "ChangeDogs" button.  // 10:11:29.703 index.js:18 CATS rendering..  --> Press "ChangeDogs" button.  // 10:11:33.143 index.js:13 Dogs rendering.. --> Press "ChangeCats" button.  // 10:11:33.143 index.js:18 CATS rendering..  --> Press "ChangeCats" button.  // Selectors - Memoized version RESELECT middleware'i ile..  const dogsDataMemo = createSelector(    state => state.pets.dogs,    dogs => dogs  );  const catsDataMemo = createSelector(    state => state.pets.cats,    cats => cats  );  const dogsData = useSelector(dogsDataMemo)  const catsData = useSelector(catsDataMemo)  // Components  const Dogs = ({ dogsData }) => {    console.log("Dogs rendering..");    return <h1>{dogsData}</h1>;  };  const Cats = ({ catsData }) => {    console.log("Cats rendering..");    return <h1>{catsData}</h1>;  );}export default ReduxDeneme;1. 场景:我使用了经典的、非记忆的样式选择器。控制台上有6次console.log。(第一次打开2次-正常-,点击“换狗”按钮2次,点击“换猫”按钮2次)。这意味着发生了 6 次重新渲染。2. 场景:我使用reselect了中间件来防止不必要的重新渲染。但是,它不起作用或者我误解了reselect.有人可以解释正确的方法或我在哪里做错了吗?
查看完整描述

2 回答

?
HUX布斯

TA贡献1876条经验 获得超6个赞

您正在组件内定义选择器。你应该在外面做(例如你的减速器附近的某个地方)。


目前,您正在每次渲染后重新创建选择器。这是一个更好的方法:


// inside reducer.js


  export const petsSel = state => state.pets;

  export const dogsDataMemo = createSelector(

    petsSel,

    pets => pets.dogs

  );

  export const catsDataMemo = createSelector(

    petsSel,

    pets => pets.cats

  );

根据您的代码添加了带有工作示例的代码框:https ://codesandbox.io/s/delicate-snowflake-5ssrw


为了实现你想要的,你还需要使用 React.memo ( https://reactjs.org/docs/react-api.html#reactmemo ):


const Dogs = React.memo(({ dogsData }) => {

  console.log("Dogs rendering..");

  return <h1>{dogsData}</h1>;

});


查看完整回答
反对 回复 2022-05-22
?
PIPIONE

TA贡献1829条经验 获得超9个赞

首先,我非常感谢@tudor 的努力。他说的都是对的。


但是,我想证明 Reselect 有效。


场景 1 - 非记忆


import React, { memo } from "react";

import { useSelector, useDispatch } from "react-redux";

// import { catsDataMemo, dogsDataMemo } from "./selectors";


// Components

const Dogs = memo(({ dogsData }) => {

  console.log("Dogs rendering..");

  return <h1>{dogsData}</h1>;

});


const Cats = memo(({ catsData }) => {

  console.log("Cats rendering..");

  return <h1>{catsData}</h1>;

});


function ReduxDeneme() {

  // Standart useSelector without MEMOIZED

  const dogsData = useSelector(

    state => state.pets.dogs,

    console.log("dogsData Selector çalıştı.")

  );

  const catsData = useSelector(

    state => state.pets.cats,

    console.log("catsData Selector çalıştı.")

  );


  // Actions


  const dispatch = useDispatch();

  const changeDogs = () => dispatch({ type: "CHANGE_DOGS" });

  const changeCats = () => dispatch({ type: "CHANGE_CATS" });


  const noChangeCats = () =>

    dispatch({ type: "NO_CHANGE_CATS", payload: catsData });


  return (

    <div>

      <Dogs dogsData={dogsData} />

      <Cats catsData={catsData} />

      <button onClick={changeDogs}>Change Dogs</button>

      <button onClick={changeCats}>Change CATS</button>

      <button onClick={noChangeCats}>No Change</button>

    </div>

  );

}


export default memo(ReduxDeneme);

当心!当您单击“更改狗”按钮时,控制台中的输出将是:


dogsData Selector çalıştı.

catsData Selector çalıştı.

Dogs rendering..

或者当您单击“更改猫”按钮时,输出将是:


dogsData Selector çalıştı.

catsData Selector çalıştı.

Cats rendering..

无论您按什么按钮,这两个 useSelectors 都将起作用,正如您从 console.log 中看到的那样


场景 2 - 使用重新选择中间件进行记忆


首先,正如@tudor.gergely 提到的,我们将记忆选择器分离到另一个文件中。


小心点!您必须定义对象的正确路径。


// selectors.js


import { createSelector } from "reselect";


export const dogsDataMemo = createSelector(

  state => state.pets.dogs, // BE CAREFULL while defining..

  dogs => {

    console.log("DogsDataMemo has worked.");

    return dogs;

  }

);

export const catsDataMemo = createSelector(

  state => state.pets.cats, // BE CAREFULL while defining..

  cats => {

    console.log("CatsDataMemo has worked.");

    return cats;

  }

);

然后,我们将这个文件导入到 main.js 文件中,并再次将 useSelector 与我们的记忆选择器一起使用:


import React, { memo } from "react";

import { useSelector, useDispatch } from "react-redux";

import { catsDataMemo, dogsDataMemo } from "./selectors";


// Components

const Dogs = memo(({ dogsData }) => {

  console.log("Dogs rendering..");

  return <h1>{dogsData}</h1>;

});


const Cats = memo(({ catsData }) => {

  console.log("Cats rendering..");

  return <h1>{catsData}</h1>;

});


function ReduxDeneme() {

  const dogsData = useSelector(dogsDataMemo);

  const catsData = useSelector(catsDataMemo);


  // Actions

  const dispatch = useDispatch();

  const changeDogs = () => dispatch({ type: "CHANGE_DOGS" });

  const changeCats = () => dispatch({ type: "CHANGE_CATS" });


  const noChangeCats = () =>

    dispatch({ type: "NO_CHANGE_CATS", payload: catsData });


  return (

    <div>

      <Dogs dogsData={dogsData} />

      <Cats catsData={catsData} />

      <button onClick={changeDogs}>Change Dogs</button>

      <button onClick={changeCats}>Change CATS</button>

      <button onClick={noChangeCats}>No Change</button>

    </div>

  );

}


export default memo(ReduxDeneme);

和最终输出:


单击“更改狗”按钮时:

DogsDataMemo has worked.

Dogs rendering

单击“更改猫”按钮时:

CatsDataMemo has worked.

Cats rendering..


查看完整回答
反对 回复 2022-05-22
  • 2 回答
  • 0 关注
  • 171 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号