在我的react / redux / redux-thunk应用中,我有一个reducer来管理包含类似于以下内容的列表的状态:
state = {
stuff: [
{
id: 1,
color: "blue",
shape: "square"
},
{
id: 2,
color: "red",
shape: "circle"
},
{
id: 3,
color: "yellow",
shape: "square"
},
]
};
我想创建可以在我的应用程序中使用的辅助函数,这些函数根据传递给函数的参数返回商店中已过滤的商品清单。例如:
getStuffByShape("square"); // returns array with stuff 1 and 3
getStuffByColor("red"); // returns array with stuff 2
我读到我可以创建一个单例存储,可以根据需要将其导入到不同的文件中,但是不建议这样做。我目前不进行任何服务器端渲染,但我不想将来限制选择。
我已经阅读了有关创建选择器和reselect
包的信息,但是这些示例仅显示了带有状态参数的函数,尚不清楚是否可以传递附加的任意参数。
我可以从连接的组件传递状态作为参数,但是我可能想在其他地方使用这些函数,例如其他辅助功能。
答案 0 :(得分:0)
您可以创建一个parameterized selector,我的首选方法是可以记住的咖喱方法:
const { Provider, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { createSelector } = Reselect;
const initialState = {
stuff: [
{
id: 1,
color: 'blue',
shape: 'square',
},
{
id: 2,
color: 'red',
shape: 'circle',
},
{
id: 3,
color: 'yellow',
shape: 'square',
},
],
};
const reducer = (state) => state;
//helper
const createFilterBy = (field, value) => (item) =>
value ? item[field] === value : true;
//selectors
const selectStuff = (state) => state.stuff;
const createSelectFiltered = (filterFn) =>
createSelector([selectStuff], (stuff) =>
stuff.filter(filterFn)
);
const createSelectByColor = (color) =>
createSelector(
[createSelectFiltered(createFilterBy('color', color))],
(x) => x
);
const createSelectByShape = (shape) =>
createSelector(
[createSelectFiltered(createFilterBy('shape', shape))],
(x) => x
);
//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 List = React.memo(function List({ items }) {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{JSON.stringify(item)}</li>
))}
</ul>
);
});
const SelectList = React.memo(function SelectList({
label,
value,
setter,
options,
}) {
return (
<label>
{label}
<select
value={value}
onChange={({ target: { value } }) =>
setter(value === 'all' ? undefined : value)
}
>
<option value="all">all</option>
{options.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
</label>
);
});
const colors = ['blue', 'red', 'yellow'];
const shapes = ['square', 'circle'];
const App = () => {
const [color, setColor] = React.useState();
const [shape, setShape] = React.useState();
const selectByColor = React.useMemo(
() => createSelectByColor(color),
[color]
);
const selectByShape = React.useMemo(
() => createSelectByShape(shape),
[shape]
);
const byColor = useSelector(selectByColor);
const byShape = useSelector(selectByShape);
return (
<div>
<div>
<SelectList
label="color"
value={color}
setter={setColor}
options={colors}
/>
<SelectList
label="shape"
value={shape}
setter={setShape}
options={shapes}
/>
</div>
<div>
<h4>color</h4>
<List items={byColor} />
<h4>shape</h4>
<List items={byShape} />
</div>
</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>