使用 args 或 props 使用选择器从 Redux 派生数据

Using args or props to derive data from Redux using selectors

TL;DR: 我试图在我的选择器中使用 id 和类型参数,但参数是 undefined。使用 reselectcreateStructuredSelector 的正确方法是什么?

我正在使用 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));