我今天尝试使用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>;
};
// Actions
const dispatch = useDispatch();
const changeDogs = () => dispatch({ type: "CHANGE_DOGS" });
const changeCats = () => dispatch({ type: "CHANGE_CATS" });
return (
<div>
<Dogs dogsData={dogsData} />
<Cats catsData={catsData} />
<button onClick={changeDogs}>Change Dogs</button>
<button onClick={changeCats}>Change CATS</button>
</div>
);
}
export default ReduxDeneme;
reselect
中间件来防止不必要的重新渲染。但是,它不起作用,或者我误解了reselect
的含义。有人可以解释正确的方法还是我在哪里做错了?
答案 0 :(得分:1)
您正在定义组件内部的选择器。您应该在室外(例如减速机附近的地方)进行操作。
当前,您正在每个渲染之后重新创建选择器。这是一种更好的方法:
// 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>;
});
答案 1 :(得分:1)
首先,非常感谢@tudor的努力。他的所有话都是正确的。
但是,我想证明重新选择有效。
场景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..
无论您按下什么按钮,两个useSelector都可以正常工作,就像您从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..