[英]How to filter an array object in a reducer without affecting the actual state
I'm trying to filter an object from an array (redux reducer),我正在尝试从数组(redux reducer)中过滤 object,
const data = [
{id: 0, name: 'Printed Men black Shirt', itemCode: 1000, price: 530, currency: '$', manufacturer: 'ColorWorld'},
{id: 1, name: 'Denim blue white shorts', itemCode: 1001, price: 230, currency: '$', manufacturer: 'ColorWorld'},
{id: 2, name: 'Solid Men blue pants', itemCode: 1003, price: 1530, currency: '$', manufacturer: 'Mecrono Hipli'},
{id: 3, name: 'Checkerd Men Blue Shorts', itemCode: 1300, price: 2530, currency: '$', manufacturer: 'Mecrono Hipli Mini'},
{id: 4, name: 'Self Designed Pant', itemCode: 1056, price: 130, currency: '$', manufacturer:
];
export const listProducts = (state = data, action) => {
switch(action.type){
case LIST_ALL_PRODUCTS: {
return state;
}
case SEARCH_PRODUCT: {
return state.filter((e)=> e.name.includes(action.payload))
}
default:
return state
}
}
This reducer always updates the actual state.这个减速器总是更新实际的 state。 Why this is not making a new filtered array?为什么这不制作一个新的过滤数组?
You can solve your issue by converting the state data structure to an object and maintain a separate property in redux state say filteredData
.您可以通过将 state 数据结构转换为 object 来解决您的问题,并在 redux filteredData
中维护一个单独的属性。
Like this像这样
const initialState = {
data: [
{
id: 0,
name: 'Printed Men black Shirt',
itemCode: 1000,
price: 530,
currency: '$',
manufacturer: 'ColorWorld',
},
{
id: 4,
name: 'Self Designed Pant',
itemCode: 1056,
price: 130,
currency: '$',
manufacturer: '',
},
],
filteredData: [],
}
export const listProducts = (state = initialState, action) => {
switch (action.type) {
case LIST_ALL_PRODUCTS: {
return state
}
case SEARCH_PRODUCT: {
return { ...state, filteredData: state.data.filter((e) => e.name.includes(action.payload)) }
}
default:
return state
}
}
Another option另外的选择
Use single source of data in redux and do the filtering logic in the component itself.在 redux 中使用单一数据源,并在组件本身中执行过滤逻辑。 See sample demo here if it helps.如果有帮助,请参阅此处的示例演示。
As I mentioned in the comment, you can also separately store the filter itself and do the filtering not in the reducer, but in the component:正如我在评论中提到的,您还可以单独存储过滤器本身,而不是在减速器中进行过滤,而是在组件中进行过滤:
Example reducers:减速器示例:
export const listProducts = (state = data, action) => {
switch (action.type) {
default:
return state;
}
};
export const productNameFilter = (state = "", action) => {
switch (action.type) {
case SEARCH_PRODUCT: {
return action.payload.toLowerCase();
}
default:
return state;
}
};
// assuming root reducer is:
// combineReducers({ listProducts, productNameFilter })
In the productNameFilter reducer, the SEARCH_PRODUCT
action's payload should contain the product name filter.在 productNameFilter reducer 中, SEARCH_PRODUCT
操作的有效负载应包含产品名称过滤器。 Resetting the search filter is as simple as setting the state to ''
.重置搜索过滤器就像将 state 设置为''
一样简单。
Example component, using hooks:示例组件,使用钩子:
const ProductList = () => {
const products = useSelector((state) => state.listProducts);
const productFilter = useSelector((state) => state.productNameFilter);
const shownProducts = products.filter((product) =>
product.name.toLowerCase().includes(productFilter.toLowerCase())
);
return (
<ul>
{shownProducts.map((p) => (
<p key={p.id}>{p.name}</p>
))}
</ul>
);
};
or with connect
:或使用connect
:
const ProductList = ({ products, productFilter }) => {
const shownProducts = products.filter((product) =>
product.name.toLowerCase().includes(productFilter)
);
return (
<ul>
{shownProducts.map((p) => (
<p key={p.id}>{p.name}</p>
))}
</ul>
);
};
export default connect(ProductList)((state) => ({
products: state.listProducts,
productFilter: state.productNameFilter,
}));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.