我们知道,如果我们想要重新渲染一个由 react-redux 连接的 react 组件,我们应该在调度相关的 action 时在 reducer 中返回一个新的数组。我的问题是当 redux reducer 不返回新数组时,为什么 react 组件可以重新渲染? 当我点击应用组件按钮时,第一个应用名称变成了'aaa',为什么???
动作:
export function setAppName(name: string) {
return {
type: 'SET_APP_NAME',
name,
}
}
减速器:
export function appInfos(state = {
appInfos: [
{name: 'ccc'},
{name: 'ddd'},
]
}, action: any) {
switch(action.type) {
case 'SET_APP_NAME':
// just return origin array, not a new array
const appInfos = state.appInfos;
appInfos[0].name = action.name
return Object.assign({}, state, { appInfos })
default:
return state;
}
}
组件应用:
function mapStateToProps(state: any) {
return {
app: state.appInfos
}
}
function App() {
const { app } = useSelector(mapStateToProps)
const dispatch = useDispatch()
const onClick = useCallback(() => {
dispatch(setAppName('aaa'))
}, [dispatch])
return (
<div className="app">
{app.appInfos.map((info: any) => {
return <div key={info.name}>{info.name}</div>
})}
<button onClick={onClick}>click</button>
</div>
);
}
容器和存储:
const store = createStore(combineReducers({
appInfos
}))
ReactDOM.render(
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>,
document.getElementById('root')
);
答案 0 :(得分:1)
您混淆了 connect
和 useSelector
的使用,这导致了不必要的渲染。
connect
接受一个 mapStateToProps
函数作为参数,它必须返回一个对象,因为所有字段都将成为组件的新道具。如果任何单个字段更改为新引用,该组件将重新呈现:
https://react-redux.js.org/using-react-redux/connect-mapstate
然而,useSelector
接受一个必须返回 one 值的选择器函数,如果该 one 引用更改为新值,它将重新呈现:
https://react-redux.js.org/api/hooks#equality-comparisons-and-updates
现在,您正在编写一个总是返回一个新对象引用的函数。您的函数将总是在每个分派动作后运行,因此它会总是强制组件重新渲染。
改为:
function selectAppInfo(state) {
return state.appInfos
}