Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

212
Views
How to avoid component update caused by useSelector hook

In my Table component I'm getting data from redux store with useSelector hook.

const info = useSelector(state => {
        if (type === 'catalog') {
            return store.getState().catalog.products
        }
        if (type === 'category') {
            return store.getState().categories.categories
        }
    }) 

Then I'm processing data to correct type

React.useEffect(() => {
      if(info.length) {
              const prods:any = []
              info.forEach((product: any) => {
                  const productObj: any = {}
                  productObj._prodid = product?._id
                  productObj.image = product?.catalogProduct?.image
                  productObj.category = product?.catalogProduct?.category.name
                  productObj.name = product?.catalogProduct?.name
                  productObj.pricePerPiece = product?.catalogProduct?.pricePerPiece
                  productObj.pricePerPackage = product?.catalogProduct?.pricePerPackage
                  productObj.address = product?.address
                  productObj.piecesAtStorage = product?.piecesAtStorage

                  prods.push(productObj)
              })

              setData(prods)
      }
    }, [info])

It takes 3 re-renders.

First rerender - initial data of useState

Second rerender - initial data from useSelector

Third rerender - set data from useSelector into useState

And the output looks like this.

enter image description here

Is it possible to avoid rerender caused by useSelector?

about 4 years ago · Juan Pablo Isaza
2 answers
Answer question

0

You could combine the 2 things in one selector:

const { Provider, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { createSelector } = Reselect;

const initialState = {
  catalog: {
    products: [{ _id: 1 }, { _id: 2 }],
    categories: [{ _id: 3 }, { _id: 4 }],
  },
};
const reducer = (state) => {
  return state;
};
//selectors
const selectCatalog = (state) => state.catalog;
//select product or categories and map them
const selectData = createSelector(
  [selectCatalog, (_, type) => type],
  (catalog, type) => {
    const data =
      type === 'catalog'
        ? catalog.products
        : type === 'category'
        ? catalog.categories
        : [];
    //use map instead of forEach
    return data.map((item) => ({
      //SO snippet has old babel so removed optional chaining
      //  you can put it back in your code
      _prodid: item._id,
      //you can figure out the other props
    }));
  }
);
//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 App = () => {
  const [type, setType] = React.useState('catalog');
  const data = useSelector((state) =>
    selectData(state, type)
  );
  console.log('render app', type);
  return (
    <div>
      <select
        value={type}
        onChange={(e) => setType(e.target.value)}
      >
        <option value="catalog">catalog</option>
        <option value="category">category</option>
      </select>
      <pre>{JSON.stringify(data, undefined, 2)}</pre>
    </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>

about 4 years ago · Juan Pablo Isaza Report

0

Have you tried shallowEqual function?

import { shallowEqual, useSelector } from 'react-redux'

const selectedData = useSelector(selectorReturningObject, shallowEqual)

The problem is it returns a new array each time it runs. As for object and array, those with same properties/values are technically not same. This is why you are seeing same empty array twice.

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!