【问题标题】:Filter item on item list that is on state using useState and useEffect使用 useState 和 useEffect 过滤处于状态的项目列表中的项目
【发布时间】:2021-04-20 14:13:51
【问题描述】:

我的应用程序上有一个项目列表,我正在尝试为每个单击创建一个详细信息页面。此外,我没有管理如何使用 useState 和 useEffect 使用 typescript,我可以只使用 componentDidMount 来管理,这不是我的目标。

在我的州,称为MetricState,我有"metrics",我在某些地方看到我也应该在我的州添加"selectedMetric"。我认为这是一个奇怪的解决方案,因为我只想能够通过“在处于状态的指标列表上选择 id x 的指标”的操作来调用调度。

这是代码框,当您单击“详细信息”按钮时,您会看到未打印来自该州的所选指标的名称:https://codesandbox.io/s/react-listing-forked-6sd99

这是我的州:

export type MetricState = {
  metrics: IMetric[];
};

调度调用的我的 actionCreators.js 文件

export function fetchMetric(catalog, metricId) {
  const action = {
    type: ACTION_TYPES.CHOOSE_METRIC,
    payload: []
  };
  return fetchMetricCall(action, catalog, metricId);
}

const fetchMetricCall = (action, catalog, metricId) => async (dispatch) => {
  dispatch({
    type: action.type,
    payload: { metrics: [catalog.metrics.filter((x) => x.name === metricId)] } //contains the data to be passed to reducer
  });
};

最后是 MetricsDeatail.tsx 页面,我尝试使用来自路由参数的 id 过滤所选项目:

const metricId = props.match.params.metricId;
  const catalog = useSelector<RootState, MetricState>(
    (state) => state.fetchMetrics
  );

  const selectedMetric: IMetric = {
    name: "",
    owner: { team: "" }
  };
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(appReducer.actionCreators.fetchMetric(catalog, metricId));
  }, []);

【问题讨论】:

    标签: reactjs typescript react-redux react-hooks


    【解决方案1】:

    在我的状态,称为 MetricState,我有“指标”,我在某些地方看到我也应该在我的状态中添加一个“selectedMetric”。我认为这是一个奇怪的解决方案,因为我只想能够通过“在状态上的指标列表上选择 id x 的指标”的操作来调用调度。

    我同意你的看法。 metricId 来自通过props 的 URL,因此它也不需要处于状态。您希望每条数据都有一个“单一事实来源”。

    为了使用这种设计模式,您的 Redux 商店需要能够:

    • 根据 ID 获取并存储单个指标。
    • 按 id 从商店中选择一个选择指标。

    我通常发现使用键控对象状态 (Record&lt;string, IMetric&gt;) 更容易,但 array 也可以。

    您的组件应如下所示:

    const MetricDetailsPage: React.FC<MatchProps> = (props) => {
      const metricId = props.match.params.metricId;
    
      // just select the one metric that we want
      // it might be undefined initially
      const selectedMetric = useSelector<RootState, IMetric | undefined>(
        (state) => state.fetchMetrics.metrics.find(metric => metric.name === metricId )
      );
    
      const dispatch = useDispatch();
    
      useEffect(() => {
        dispatch(appReducer.actionCreators.fetchMetric(metricId));
      }, []);
    
      return (
        <div>
          <Link to={`/`}>Go back to main page</Link>
          Here should print the name of the selected metric:{" "}
          <strong>{selectedMetric?.name}</strong>
        </div>
      );
    };
    
    export default MetricDetailsPage;
    

    但是您应该重新设计您的动作创建者,这样您就不会在组件中选择整个catalog,然后将其作为参数传递给动作创建者。

    【讨论】:

    • 嗨琳达!感谢您的帮助!我还有一个问题。在您的 fakeApi 上,您调用“DATA”,但在我的情况下,我想获取商店中的数据,因为我的数据不会在真实应用程序上被模拟。对此有何建议? :) 我可以只使用您解释的 useSelector 的一部分来检索指标并且它可以工作,但我想直接在 actionCreators.js 上调度一个操作来对状态执行此过滤器
    • 如果数据已经存在于 store 中,则不需要 dispatch 任何 action。这个想法是状态将存储所有先前加载的指标,因此如果您从“/one”更改为“/two”,那么您不需要更改存储中的任何内容。但是,当您处理 react-router 时,您需要使其能够独立加载每个页面。你不能指望在登陆“/one”之前已经加载了完整的列表。这就是为什么我认为会有一些 API 调用会加载单个指标。
    猜你喜欢
    • 1970-01-01
    • 2021-03-07
    • 1970-01-01
    • 1970-01-01
    • 2020-07-08
    • 2020-04-16
    • 2017-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多