使用 args 或 props 使用选择器从 Redux 派生数据
Using args or props to derive data from Redux using selectors
TL;DR: 我试图在我的选择器中使用 id 和类型参数,但参数是 undefined
。使用 reselect
和 createStructuredSelector
的正确方法是什么?
我正在使用 reselect
编写选择器来获取 React 组件所需的数据。数据以 key/value 格式存储,其中键由 动态 ID 和类型值 组成。对象看起来像这样:
customView: {
'viewBy:deviceProfileId&id:5923f82a-80c2-4c88-bd0e-c105ad989ab2': { // type = 'deviceProfileId' & id = '5923f82a-80c2-4c88-bd0e-c105ad989ab2'
list: { ... },
meta: { ... },
error: { ... }
}
用户输入 id 和类型并触发从 API 获取数据。我有基本的选择器,但我一直在尝试使用这些动态值获取每个条目所需的数据——它们仍然未定义。我错过了什么?有没有更好的方法来完成这个?
// reducer.js : Fn to generate key
export const customViewKey = ({ customViewType, id } = {}) => {
const typeKey = (customViewType && `viewBy:${customViewType}`) || '';
const idKey = (id && `id:${id}`) || '';
const namespace = `${typeKey}&${idKey}`;
return `${namespace}`;
};
// selector.js
const getCustomView = ({ customView }) => customView; // Basic selector works
export const getCustomViewData = createSelector(
getCustomView,
(customView, id, customViewType) => { // id and customViewType are undefined
return customView && customView[customViewKey({ customViewType, id })];
}
);
// index.js
export const CustomViewsPage = ({ classes, getCustomView, customViewMap, customViewType, id }) => {
const [idValue, setIdValue] = useState('');
const [type, setType] = useState('');
const handleTypeChange = (e) => {
let typeEntered = e ? e.value : '';
setType(typeEntered);
};
const handleInputChange = (e) => {
setIdValue(e.target.value);
};
const handleSubmit = (e) => { // Fn called when user hits submit
e.preventDefault();
getCustomView({ id: idValue, customViewType: type });
};
return (
<div>
<form onSubmit={handleSubmit} className={classes.customViewForm}>
<div>
<p>Select type of custom view:</p>
<Select
placeholder="View messages by"
options={customViewTypes}
onChange={handleTypeChange}
isClearable
/>
</div>
<div>
<p>Enter ID for device, project or device profile:</p>
<InputBase
placeholder="5923f82a-80c2-4c88-bd0e-c105ad989ab2"
required
onChange={handleInputChange}
fullWidth
/>
</div>
<label htmlFor="create-custom-view-btn">
<Input id="create-custom-view-btn" type="submit" />
<Button
component="span"
variant="outlined"
color="primary"
endIcon={<SendRounded />}
onClick={handleSubmit}
>
Create view
</Button>
</label>
</form>
</div>
const mapDispatchToProps = {
getCustomView: requestCustomView,
};
const mapStateToProps = createStructuredSelector({
customViewMap: getCustomViewMap,
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(CustomViewsPage));
是的,你的 createSelector
打错了。
如果您希望您的“输出函数”接受 3 个参数,那么您需要编写 3 个单独的“输入函数”。每个输入函数都应提取并 return 一个值,这些值将成为输出函数的参数。
所以,你需要这样的东西:
export const getCustomViewData = createSelector(
getCustomView,
// these should also read values from `state` or any other args
getId,
getCustomViewType,
(customView, id, customViewType) => {
// return calculation results here
}
);
有关如何使用 Reselect 的更多详细信息,请参阅 Redux 文档 Deriving Data with Selectors 使用指南页面。
由于@markerikson 的回答和这个 blog,我找到了解决方案。
这些是我正在使用的选择器:
const getCustomView = ({ customView }) => customView;
const getId = (_, id) => id;
const getCustomViewType = (_, id, customViewType) => customViewType;
export const getCustomViewData = createSelector(
getCustomView,
getId,
getCustomViewType,
(customView, id, customViewType) => {
return customView && customView[customViewKey({ customViewType, id })]; // WORKS!
}
);
export const getCustomViewMap = createSelector(getCustomViewData, getDomainMap);
我正在使用 useSelector
以这种方式从我的组件调用选择器:
const selectedCustomView = useSelector(state => getCustomViewMap(state, idValue, type));
TL;DR: 我试图在我的选择器中使用 id 和类型参数,但参数是 undefined
。使用 reselect
和 createStructuredSelector
的正确方法是什么?
我正在使用 reselect
编写选择器来获取 React 组件所需的数据。数据以 key/value 格式存储,其中键由 动态 ID 和类型值 组成。对象看起来像这样:
customView: {
'viewBy:deviceProfileId&id:5923f82a-80c2-4c88-bd0e-c105ad989ab2': { // type = 'deviceProfileId' & id = '5923f82a-80c2-4c88-bd0e-c105ad989ab2'
list: { ... },
meta: { ... },
error: { ... }
}
用户输入 id 和类型并触发从 API 获取数据。我有基本的选择器,但我一直在尝试使用这些动态值获取每个条目所需的数据——它们仍然未定义。我错过了什么?有没有更好的方法来完成这个?
// reducer.js : Fn to generate key
export const customViewKey = ({ customViewType, id } = {}) => {
const typeKey = (customViewType && `viewBy:${customViewType}`) || '';
const idKey = (id && `id:${id}`) || '';
const namespace = `${typeKey}&${idKey}`;
return `${namespace}`;
};
// selector.js
const getCustomView = ({ customView }) => customView; // Basic selector works
export const getCustomViewData = createSelector(
getCustomView,
(customView, id, customViewType) => { // id and customViewType are undefined
return customView && customView[customViewKey({ customViewType, id })];
}
);
// index.js
export const CustomViewsPage = ({ classes, getCustomView, customViewMap, customViewType, id }) => {
const [idValue, setIdValue] = useState('');
const [type, setType] = useState('');
const handleTypeChange = (e) => {
let typeEntered = e ? e.value : '';
setType(typeEntered);
};
const handleInputChange = (e) => {
setIdValue(e.target.value);
};
const handleSubmit = (e) => { // Fn called when user hits submit
e.preventDefault();
getCustomView({ id: idValue, customViewType: type });
};
return (
<div>
<form onSubmit={handleSubmit} className={classes.customViewForm}>
<div>
<p>Select type of custom view:</p>
<Select
placeholder="View messages by"
options={customViewTypes}
onChange={handleTypeChange}
isClearable
/>
</div>
<div>
<p>Enter ID for device, project or device profile:</p>
<InputBase
placeholder="5923f82a-80c2-4c88-bd0e-c105ad989ab2"
required
onChange={handleInputChange}
fullWidth
/>
</div>
<label htmlFor="create-custom-view-btn">
<Input id="create-custom-view-btn" type="submit" />
<Button
component="span"
variant="outlined"
color="primary"
endIcon={<SendRounded />}
onClick={handleSubmit}
>
Create view
</Button>
</label>
</form>
</div>
const mapDispatchToProps = {
getCustomView: requestCustomView,
};
const mapStateToProps = createStructuredSelector({
customViewMap: getCustomViewMap,
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(CustomViewsPage));
是的,你的 createSelector
打错了。
如果您希望您的“输出函数”接受 3 个参数,那么您需要编写 3 个单独的“输入函数”。每个输入函数都应提取并 return 一个值,这些值将成为输出函数的参数。
所以,你需要这样的东西:
export const getCustomViewData = createSelector(
getCustomView,
// these should also read values from `state` or any other args
getId,
getCustomViewType,
(customView, id, customViewType) => {
// return calculation results here
}
);
有关如何使用 Reselect 的更多详细信息,请参阅 Redux 文档 Deriving Data with Selectors 使用指南页面。
由于@markerikson 的回答和这个 blog,我找到了解决方案。
这些是我正在使用的选择器:
const getCustomView = ({ customView }) => customView;
const getId = (_, id) => id;
const getCustomViewType = (_, id, customViewType) => customViewType;
export const getCustomViewData = createSelector(
getCustomView,
getId,
getCustomViewType,
(customView, id, customViewType) => {
return customView && customView[customViewKey({ customViewType, id })]; // WORKS!
}
);
export const getCustomViewMap = createSelector(getCustomViewData, getDomainMap);
我正在使用 useSelector
以这种方式从我的组件调用选择器:
const selectedCustomView = useSelector(state => getCustomViewMap(state, idValue, type));