使用 redux store.subscribe 运行 React 功能组件

Posted

技术标签:

【中文标题】使用 redux store.subscribe 运行 React 功能组件【英文标题】:Running a React functional component with redux store.subscribe 【发布时间】:2021-06-09 16:09:01 【问题描述】:

考虑下面的 react 代码(也包括 redux)

store = createStore(todoApp) ;
store.subscribe(App);

export default function App()
  .....

这意味着对于我的 App 功能组件中发生的每个调度操作,App 必须呈现,因为 subscribe 执行封闭的 function 。然而,我观察到的是,虽然该函数执行 html 组件并没有得到更新,并且即使在多次调度操作之后,从第一次渲染仍然保持不变。谁能解释这种行为?

【问题讨论】:

这不是你在 react 中使用 redux 的方式,你可以使用钩子 useSelectoruseDispath 或 HOC connect 两者都和 Provider 一起使用 【参考方案1】:

这不是您将 React 应用程序连接到 redux 存储的方式。这是一个使用 Provider 和 react-redux 钩子的示例应用程序:

//you would import these with
//  import Provider from 'react-redux'
const  Provider, useDispatch, useSelector  = ReactRedux;
const  createStore, applyMiddleware, compose  = Redux;
const  createSelector  = Reselect;
const  memo, useMemo, useCallback  = React;

const initialState = 
  counters: [
     id: 1, count: 1 ,
     id: 2, count: 1 ,
     id: 3, count: 1 ,
  ],
;
//action types
const ADD = 'ADD';
//action creators
const add = (id) => (
  type: ADD,
  payload: id,
);
const reducer = (state,  type, payload ) => 
  if (type === ADD) 
    return 
      ...state, //not needed in this case but usually is
      counters: state.counters.map(
        (counter) =>
          counter.id === payload
            ?  ...counter, count: counter.count + 1 
            : counter //do not update this counter (not the right id)
      ),
    ;
  
  return state;
;
//selectors
const selectCounters = (state) => state.counters;
const createSelectCounterById = (counterId) =>
  createSelector(
    [selectCounters], //re use select counters
    (
      counters //got the counters, find the right counter
    ) => counters.find(( id ) => id === counterId)
  );
//select sum of all counters
const selectSum = createSelector(
  [selectCounters], //re use select counters
  (counters) =>
    //reduce counters array to a number
    counters.reduce(
      (result, counter) => result + counter.count,
      0
    )
);
//creating store with redux dev tools
const composeEnhancers =
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  reducer,
  initialState,
  composeEnhancers(
    applyMiddleware(() => (next) => (action) =>
      next(action)
    )
  )
);
const Counter = memo(function Counter( id, addAction ) 
  const selectCounter = useMemo(
    () => createSelectCounterById(id),
    [id]
  );
  const counter = useSelector(selectCounter);
  return (
    <li>
      counter.count
      <button onClick=() => addAction(id)>+</button>
    </li>
  );
);
const Total = memo(function Total() 
  const sum = useSelector(selectSum);
  return <h3>sum</h3>;
);
const App = () => 
  const counters = useSelector(selectCounters);
  const dispatch = useDispatch();
  const addAction = useCallback(
    (id) => dispatch(add(id)),
    //dispatch is not really a dependency but
    //  linter doesn't know that and adding
    //  it doesn't change behavior
    [dispatch]
  );
  return (
    <div>
      <Total />
      <ul>
        counters.map(( id ) => (
          //id property here is not html id element property
          <Counter key=id id=id addAction=addAction />
        ))
      </ul>
    </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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
<div id="root"></div>

【讨论】:

感谢您的回复。但是为什么有问题的代码不起作用?因为对于每次调度,商店都被订阅并且封闭的(APP函数)函数应该重新执行 @ShaikWasef 再说一遍:That is not how you connect your React application to the redux store. 你的组件 App 将由 Redux 调用,而不是由 React 调用,因此不会呈现任何内容,因为 App 函数没有什么特别之处,它只会在 React 调用时向 DOM 渲染一些东西。

以上是关于使用 redux store.subscribe 运行 React 功能组件的主要内容,如果未能解决你的问题,请参考以下文章

[Redux/Mobx] 说说Redux的实现流程

react-redux 的使用

如何使用 React hooks 和 Redux 从 useEffect 执行 store.unsubscribe

Redux 入门学习笔记 ① —— 基本概念及使用

Redux 入门学习笔记 ① —— 基本概念及使用

redux解析