En mi componente Table, obtengo datos de la tienda redux con el gancho useSelector.
const info = useSelector(state => { if (type === 'catalog') { return store.getState().catalog.products } if (type === 'category') { return store.getState().categories.categories } })Entonces estoy procesando datos para corregir el tipo
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])Se necesitan 3 re-renderizaciones.
Primera representación: datos iniciales de useState
Segunda representación: datos iniciales de useSelector
Tercer renderizado: configure los datos de useSelector en useState
Y la salida se ve así.
¿Es posible evitar el renderizado causado por useSelector?
Podrías combinar las 2 cosas en un 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>¿Has probado la función shallowEqual ?
import { shallowEqual, useSelector } from 'react-redux' const selectedData = useSelector(selectorReturningObject, shallowEqual)El problema es que devuelve una nueva matriz cada vez que se ejecuta. En cuanto al objeto y la matriz, aquellos con las mismas propiedades/valores técnicamente no son los mismos. Es por eso que está viendo la misma matriz vacía dos veces.