Reputation: 187
What I'm trying to do is, dispatching 2 actions fetchBrand()
and fetchDistance()
. I'm having two different reducers and different action creators who are calling different APIs.
But the issue here is, it is giving the result of only one action depending on the sequence in useEffect()
. It is displaying in the console two times but results from the same API.
If a change the sequence then it will console the result for other API two times. That means my API call is getting successful for both but at a time only 1 API is calling.
It might be some functionality, but I'm not aware. How can I fix it?
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
Upvotes: 1
Views: 12162
Reputation: 19863
As suggested in the other answer, you can use something more modern library like RTK to reduce boilerplate code. But if you want to fix your code, all you need to do is create unique action types constants. You can do so by namespacing (e.g brand/FETCH_SUCCESS
etc.) them:
Action Creators:
export const fetchrequest = (name) => {
return {
type: name + FETCH_REQUEST,
};
}
...
Reducer:
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: "",
}
...
}
};
Actions:
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));
})
...
};
};
You need to do similar for distance actions/reducer as well.
PS: You need just one const dispatch = useDispatch()
.
Upvotes: 1
Reputation: 67577
My first observation is that you don't need to call useDispatch()
twice, nor do you need to have separate dispatch
-named variables. There's only one dispatch
function for the entire application, because there's only one Redux store for the entire app. So, you just need const dispatch = useDispatch()
.
Second, the actual logic looks fine and should work okay with or without the fixed dispatch
names. So, I'm not clear what the actual problem is here, and I'd recommend double-checking the implementation of those fetching functions.
update
Ah, I think I see the issue.
Both fetchBrand
and fetchDistance
are dispatching the same action type after the API call succeeds: dispatch(fetchsuccess(someData))
. Both reducers are listening for that same action type. So, both reducers are going to end up saving the first data type that comes back, then overwriting it with the second data type that comes back.
You need to have different action types for "fetched brand success" and "fetched distance success".
The other thing to note here is that the style of Redux code you're writing is outdated and going to require writing a lot more code by hand than you should. Our official Redux Toolkit package will simplify all of this code that you've got. For example, createAsyncThunk
will generate those unique action types for success/failure for each type of data that you're wanting to fetch.
Please read the Redux Fundamentals: Modern Redux with Redux Toolkit tutorial page in our docs to see how to use Redux Toolkit correctly.
Upvotes: 0