【问题标题】:How to dispatch multiple actions from same component?如何从同一个组件调度多个动作?
【发布时间】:2021-03-01 18:01:42
【问题描述】:

我想要做的是,调度 2 个动作 fetchBrand()fetchDistance()。我有两个不同的减速器和不同的动作创建者,它们调用不同的 API。

但这里的问题是,它只给出一个动作的结果,具体取决于useEffect() 中的序列。它在 console 中显示两次,但结果来自同一个 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

【问题讨论】:

    标签: reactjs redux react-redux redux-thunk


    【解决方案1】:

    正如other answer 中所建议的那样,您可以使用更现代的库(例如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));
          })
          ...
    
      };
    };
    

    您也需要对 distance 动作/reducer 执行类似操作。

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

    【讨论】:

      【解决方案2】:

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

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

      更新

      啊,我想我明白了。

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

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

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

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

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-29
      • 2020-01-25
      • 2019-03-27
      • 2020-10-23
      • 2021-12-11
      • 2021-10-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多