1
votes

Consider the below code made in react ( also including redux)

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

export default function App(){
  .....
}

which means for every dispatch action happening in my App functional component the App must render since subscribe executes the enclosed function . However what I have observed is the that though the function executes the HTML components do not get updated and remain the same from the first render even after multiple dispatch actions . Can anyone explain this behavior ?

1
That is not how you use redux with react, you can use the hooks useSelector and useDispath or the HOC connect both with Provider - HMR

1 Answers

1
votes

That is not how you connect your React application to the redux store. Here is an example application using Provider and the react-redux hooks:

//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>