慕娘9325324
我想要这个变量的副本,从第一次加载组件开始,当 foo 加载时它不会改变。当您使用useSelector(selector)react-redux 时,selector每次状态更改时都会运行,如果返回值与上次运行时不同,则 react-redux 将重新渲染组件。最简单的方法是使用一个只返回第一次调用时获得的值的选择器:const { Provider, useDispatch, useSelector } = ReactRedux;const { createStore, applyMiddleware, compose } = Redux;const initialState = { count: 0 };//action typesconst ADD = 'ADD';//action creatorsconst add = () => ({ type: ADD,});const reducer = (state, { type, payload }) => { if (type === ADD) { return { ...state, count: state.count + 1 }; } return state;};//selectorsconst selectCount = (state) => state.count; //function returning a functionconst createSelectInitialCount = () => { //initialize NONE when createSelectInitialCount is called const NONE = {}; let last = NONE; //return the selector return (state) => { //check if last value was set if (last === NONE) { //set last value (only when called the first time) last = selectCount(state); } return last; };};//creating store with redux dev toolsconst composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;const store = createStore( reducer, initialState, composeEnhancers( applyMiddleware(() => (next) => (action) => next(action) ) ));const InitialFoo = React.memo(function InitialFoo(props) { const selectInitialCount = React.useMemo(//can also use useCallback createSelectInitialCount,//createSelectInitialCount() if you use useCallback [] ); const foo = useSelector(selectInitialCount); return ( <div> <h3>initialfoo</h3> <pre> {JSON.stringify({ ...props, foo }, undefined, 2)} </pre> </div> );});const App = () => { const foo = useSelector(selectCount); const dispatch = useDispatch(); const [other, setOther] = React.useState(0); const [showFoo, setShowFoo] = React.useState(true); const remountFoo = () => { setShowFoo(false); Promise.resolve().then(() => setShowFoo(true)); }; return ( <div> <button onClick={() => dispatch(add())}> foo:{foo} </button> <button onClick={() => setOther((o) => o + 1)}> other{other} </button> <button onClick={remountFoo}>remount Foo</button> {showFoo && <InitialFoo other={other} />} </div> );};ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root'));<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script><div id="root"></div>另一种方法是使用 React.memo 和忽略 foo 的自定义比较函数来创建纯组件:const { Provider, useDispatch, useSelector } = ReactRedux;const { createStore, applyMiddleware, compose } = Redux;const initialState = { count: 0 };//action typesconst ADD = 'ADD';//action creatorsconst add = () => ({ type: ADD,});const reducer = (state, { type, payload }) => { if (type === ADD) { return { ...state, count: state.count + 1 }; } return state;};//selectorsconst selectCount = (state) => state.count;//creating store with redux dev toolsconst composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;const store = createStore( reducer, initialState, composeEnhancers( applyMiddleware(() => (next) => (action) => next(action) ) ));const InitialFoo = React.memo( function InitialFoo(props) { return ( <div> <h3>initialfoo</h3> <pre>{JSON.stringify(props, undefined, 2)}</pre> </div> ); }, //custom compare function when returning false // component will re render ({ other }, { other: newOther }) => { return other === newOther; });const InitialFooContainer = (props) => { const foo = useSelector(selectCount); //store foo in ref, will never change after mount const fooRef = React.useRef(foo); const newProps = { ...props, foo: fooRef.current }; return <InitialFoo {...newProps} />;};const App = () => { const foo = useSelector(selectCount); const dispatch = useDispatch(); const [other, setOther] = React.useState(0); const [showFoo, setShowFoo] = React.useState(true); const remountFoo = () => { setShowFoo(false); Promise.resolve().then(() => setShowFoo(true)); }; return ( <div> <button onClick={() => dispatch(add())}> foo:{foo} </button> <button onClick={() => setOther((o) => o + 1)}> other{other} </button> <button onClick={remountFoo}>remount Foo</button> {showFoo && ( <InitialFooContainer foo={foo} other={other} /> )} </div> );};ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root'));<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script><div id="root"></div>