Reputation: 43531
I have 2 different components that need to do the same kind of orchestration:
useEffect(() => {
async function fetchData() {
if (route.params['id']) {
const resConversation = await axios(`...`)
setConversationState({ ...conversationState, currentConversation: resConversation.data })
const resParticipants = await axios(`...`)
setParticipants(resParticipants.data)
const resStream = await axios(`somestuff`)
setAudioState({ ...audioState, ...resStream })
}
}
fetchData()
}, [])
The setAudioState
and setConversationState
are from useContext
.
What's the best way for me to do this and keep my code DRY?
I thought about a custom useGetConversation
hook, but I can only call that inside my component function body. Is there a better way?
Upvotes: 0
Views: 237
Reputation: 191976
If you're calls are not dependant on each other, make parallel calls with Promise.all()
, destructure the response, and then set them.
I would also avoid multiple set calls by using a reducer to set the state via useReducer
.
useEffect(() => {
if (!route.params['id']) {
return
}
async function fetchData() {
const [resConversation, resParticipants, resStream] = await Promise.a([
axios(`...`),
axios(`...`),
axios(`somestuff`)
]);
setConversationState(conversationState => ({ ...conversationState, currentConversation: resConversation.data }))
setParticipants(resParticipants.data)
setAudioState(audioState => ({ ...audioState, ...resStream }))
}
fetchData()
}, [])
If your calls are dependant on each other, make the calls first, and set the state later:
useEffect(() => {
if (route.params['id']) {
return
}
async function fetchData() {
const resConversation = await axios(`...`)
const resParticipants = await axios(`...`)
const resStream = await axios(`somestuff`)
setConversationState(conversationState => ({ ...conversationState, currentConversation: resConversation.data }))
setParticipants(resParticipants.data)
setAudioState(audioState => ({ ...audioState, ...resStream }))
}
fetchData()
}, [])
You can also bundle calling the API and setting state to a single function, but this seems a bit unreadable to me:
const callAndSet = async (axiosRequest, setter) => {
const res = await axios(axiosRequest)
setter(res)
}
useEffect(() => {
if (!route.params['id']) {
return
}
async function fetchData() {
await callAndSet(`...`, resConversation => setConversationState(conversationState => ({ ...conversationState, currentConversation: resConversation.data })))
await callAndSet(`...`, resParticipants => setParticipants(resParticipants.data))
await callAndSet(`somestuff`, resStream => setAudioState(audioState => ({ ...audioState, ...resStream })))
}
fetchData()
}, [])
Upvotes: 1