如何从同一个组件分派多个动作?

How to dispatch multiple actions from same component?

我想做的是分派 2 个动作 fetchBrand()fetchDistance()。我有两个不同的 reducer 和不同的 action creator,他们调用不同的 APIs.

但这里的问题是,它根据 useEffect() 中的顺序只给出一个动作的结果。它在 控制台 中显示两次,但结果来自相同的 API.

如果更改顺序,那么它将对其他 API 的结果进行两次控制。这意味着我的 API 通话对双方都成功,但一次只有 1 API 通话。

这可能是一些功能,但我不知道。我该如何解决?

import { Form, Input, Button, Select } from 'antd'
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'

import { fetchDistance } from '../redux/distanceAction'
import { fetchBrand } from '../redux/brandAction'

const { Option } = Select
const layout = {
  labelCol: {
    span: 8,
  },
  wrapperCol: {
    span: 10,
  },
}

const tailLayout = {
  wrapperCol: {
    offset: 10,
    span: 10,
  },
}

const UserForm = (props) => {
  const distanceList = useSelector((state) => state.distance)
  const brandList = useSelector((state) => state.brand)

  const dispatchDistance = useDispatch()
  const dispatchBrand = useDispatch()

  React.useEffect(() => {
    dispatchBrand(fetchBrand()) //dispatching action one
    dispatchDistance(fetchDistance()) //dispatching action 2
  }, [])

  const [form] = Form.useForm()

  const onFinish = (values) => {
    console.log(values)
    props.onSubmitForm(values)
    form.resetFields()
    console.log(brandList.brand)
    console.log(distanceList.distance)
    // dispatch(fetchBrand);
    // dispatch(fetchDistance);
  }

  return (
    <div className="form-layout">
      <h1> hello{distanceList.distance + brandList.brand}</h1>

      <Form {...layout} form={form} name="user-form" onFinish={onFinish}>
        <Form.Item name="name" label="Hotel Name" rules={[{ required: true }]}>
          <Input />
        </Form.Item>

        <Form.Item
          name="location"
          label="Hotel Location"
          rules={[{ required: true }]}
        >
          <Input />
        </Form.Item>

        <Form.Item name="distance" label="Distance" rules={[{ required: true }]}>
          <Select placeholder="Please select Distance" allowClear>
            <Option value="0km">0Km</Option>
            <Option value="10km">10Km</Option>
            <Option value="30">30km</Option>
          </Select>
        </Form.Item>

        <Form.Item name="brand" label="Brands" rules={[{ required: true }]}>
          <Select placeholder="Please select Brand" allowClear>
            <Option value="flip">Flipkart</Option>
            <Option value="amazon">Amazon</Option>
            <Option value="paytm">Paytm</Option>
          </Select>
        </Form.Item>

        <Form.Item {...tailLayout}>
          <Button type="primary" htmlType="submit">
            Submit
          </Button>
        </Form.Item>
      </Form>
    </div>
  )
}

export default UserForm

我的第一个观察是您不需要调用 useDispatch() 两次,也不需要具有单独的 dispatch 命名变量。整个应用只有一个 dispatch 函数,因为整个应用只有一个 Redux store。所以,你只需要 const dispatch = useDispatch().

其次,实际逻辑看起来不错,应该 可以正常工作,有或没有固定的 dispatch 名称。所以,我不清楚这里的实际问题是什么,我建议仔细检查那些获取函数的实现。

更新

啊,我想我明白了。

fetchBrandfetchDistance 都在 API 调用成功后调度 相同的 操作类型:dispatch(fetchsuccess(someData))。两个减速器都在监听相同的动作类型。因此,两个 reducer 最终都会保存返回的第一个数据类型,然后用返回的 second 数据类型覆盖它。

“品牌成功”和“距离成功”需要不同的操作类型。

这里要注意的另一件事是,您正在编写的 Redux 代码的风格已经过时,并且需要手动编写比您应该编写的更多的代码。我们的官方 Redux Toolkit 包将简化您拥有的所有这些代码。例如,createAsyncThunk 将为 success/failure 为您要获取的每种数据类型生成那些独特的操作类型。

请阅读我们文档中的 Redux Fundamentals: Modern Redux with Redux Toolkit 教程页面,了解如何正确使用 Redux Toolkit。

按照 , you can use something more modern library like RTK 中的建议减少样板代码。但是如果你想修复你的代码,你需要做的就是创建 unique 动作类型常量。您可以通过 namespacing(例如 brand/FETCH_SUCCESS 等)来实现它们:

动作创作者:

export const fetchrequest = (name) => {
  return {
    type: name + FETCH_REQUEST,
  };
}
...

减速器:

export const name = "brand/";

export const brandReducer = (state = initialState, action) => {
  switch (action.type) {
    case name + FETCH_SUCCESS:
      return {
        ...state,
        loading: false,
        brand: action.payload,
        error: "",
      }
    ...

  }
};

操作:

import { name } from "./brandReducer";

export const fetchBrand = () => {
  return function (dispatch) {
    dispatch(fetchrequest(name));
    axios
      .get(URL_HERE)
      .then((response) => {
        const brand = response;
        dispatch(fetchsuccess(name, brand));
      })
      ...

  };
};

你也需要为 距离 actions/reducer 做类似的事情。

PS: 你只需要一个 const dispatch = useDispatch().