I like the normalized CRUD of createEntityAdapter to manipulate the data, because it is very professional, but when I take out the results, I always need to use 'selectAll' to parse the data, and always want to import Adapter, which makes me Mastered the magic and at the same time endured the magic to hurt me.
import React from 'react';
import { Provider, useDispatch, useSelector, shallowEqual } from 'react-redux';
import {
configureStore,
createSlice,
createEntityAdapter
} from '@reduxjs/toolkit';
const todosAdapter = createEntityAdapter();
const { reducer, actions, name } = createSlice({
name: 'todos',
initialState: todosAdapter.getInitialState(),
reducers: {
add: todosAdapter.addOne
}
});
const store = configureStore({
reducer: {
[name]: reducer
}
});
const { add } = actions;
const Adapter = () => {
const dispatch = useDispatch();
const todos = useSelector(store => store.todos, shallowEqual);
console.log('todos: ', todos);
// { "ids": [ 1 ], "entities": { "1": { "id": 1, "todo": "one" } } }
// Can't get the original value
// I have to parse the value every time
const todosSelectors = todosAdapter.getSelectors(state => state.todos);
const todos2 = useSelector(
store => todosSelectors.selectAll(store),
shallowEqual
);
console.log('todos2: ', todos2);
// [ { "id": 1, "todo": "one" } ]
// It took me some steps to get the result I want.
return (
<div>
<button onClick={() => dispatch(add({ id: 1, todo: 'one' }))}>Add</button>
<p>{JSON.stringify(todos, null, ' ')}</p>
<p>{JSON.stringify(todos2, null, ' ')}</p>
</div>
);
};
export default () => (
<Provider store={store}>
<Adapter />
</Provider>
);
The idea is more that you define const todosSelectors = todosAdapter.getSelectors(state => state.todos); in the same file as your slice (or your rootReducer, your choice) and import it from there, not that you do it in every component file. And especially not in each component render, as that would create new selectors every time.
Also, you can use it like
const todos2 = useSelector(
- store => todosSelectors.selectAll(store),
+ todosSelectors.selectAll,
- shallowEqual
);
The shallowEqual should in this case not be necessary if I'm not mistaken, as selectAll should memoize.
Do you mean this? For the convenience of presentation, I have put them all together.
import React from 'react';
import { Provider, useDispatch, useSelector } from 'react-redux';
import {
configureStore,
createSlice,
createEntityAdapter
} from '@reduxjs/toolkit';
// Slice File
const todosAdapter = createEntityAdapter();
const todosSelectors = todosAdapter.getSelectors(state => state.todos);
const { reducer, actions, name } = createSlice({
name: 'todos',
initialState: todosAdapter.getInitialState(),
reducers: {
add: todosAdapter.addOne
}
});
const { add } = actions;
// Root Reducer
const store = configureStore({
reducer: {
[name]: reducer
}
});
const Adapter = () => {
const dispatch = useDispatch();
const todos = useSelector(todosSelectors.selectAll);
console.log('todos2: ', todos);
return (
<div>
<button onClick={() => dispatch(add({ id: 1, todo: 'one' }))}>Add</button>
<p>{JSON.stringify(todos, null, ' ')}</p>
</div>
);
};
export default () => (
<Provider store={store}>
<Adapter />
</Provider>
);
Pretty much that, yeah.
Most helpful comment
The idea is more that you define
const todosSelectors = todosAdapter.getSelectors(state => state.todos);in the same file as your slice (or your rootReducer, your choice) and import it from there, not that you do it in every component file. And especially not in each component render, as that would create new selectors every time.Also, you can use it like
The
shallowEqualshould in this case not be necessary if I'm not mistaken, asselectAllshould memoize.