admin管理员组文章数量:1322349
I'm using a hook to fetch data in my app. The hook looks something like this:
const initialState = {
response: null,
loading: true,
error: null
}
const useGetFetch(url, token, user, parser) => {
const [state, dispatch] = useReducer(fetchReducer, initialState)
useEffect (() => {
if(user){
fetch(...)
.then((data)=> data.json())
.then(dispatch(...)) // setting the state here
.catch((error) => dispatch(...)) // set error state
}
}, [user])
return [state.response, state.loading, state.error]
}
Specifically, I'm using this hook inside a form ponent, to fetch some data to use as options inside a select element.
However, I need to be able to let the user to add new options on the fly. To facilitate this, I've created a button next to the select element. If the user presses this button, a modal will pop up with another form that makes it possible create a new option. This new option is sent to the server via a post request and if successful the modal closes.
The problem I'm facing is that after the modal closes, I have no way of updating the initial data fetched with my custom data fetching hook, unless I refresh the page. Is there a way to make this happen somehow without triggering a page refresh?
My initial hunch was to use a callback function and pass it to the the useGetFetch
and bind it to the useEffect
hook. I could then pass it to the form in the modal and call the function after a successful submission, but this hasn't worked.
Another option I'm looking is the useCallback
hook, but I don't currently understand it well enough to know whether or not it could be helpful.
EDIT
Specifically what I did was create a trigger function outside the parent ponent:
const trigger = () => console.log("click")
Bound it to the fetch hook:
const useGetFetch(url, token, user, parser, trigger) => {
const [state, dispatch] = useReducer(fetchReducer, initialState)
useEffect (() => {
if(user){
fetch(...)
.then((data)=> data.json())
.then(dispatch(...)) // setting the state here
.catch((error) => dispatch(...)) // set error state
}
}, [user, trigger])
return [state.response, state.loading, state.error]
}
And passed it to the child ponent inside the parent ponent:
const trigger = () => console.log("click")
const Parent = () => {
// load a bunch of stuff
// ...
const { show, toggle } = useModal()
const [optionsData, Loading, Error] = useGetFetch(
optionsUrl,
token,
user,
parser,
trigger
)
// ...
return (
<div>
{// ...}
<button
onClick={(e) => {
e.preventDefault()
toggle()
}}
>
Add
</button>
<Modal show={show} toggle={toggle}>
<ModalForm
show={show}
toggle={toggle}
trigger={trigger}
></ModalForm>
</Modal>
{// ...}
<div>
)
}
Inside ModalForm
trigger is called after a successful post request has been performed. After closing the modal, the data is not updated. My guess was that calling trigger inside ModalForm
would have triggered useEffect
inside of the useGetFetch
but it doesn't seem to work like that.
I'm using a hook to fetch data in my app. The hook looks something like this:
const initialState = {
response: null,
loading: true,
error: null
}
const useGetFetch(url, token, user, parser) => {
const [state, dispatch] = useReducer(fetchReducer, initialState)
useEffect (() => {
if(user){
fetch(...)
.then((data)=> data.json())
.then(dispatch(...)) // setting the state here
.catch((error) => dispatch(...)) // set error state
}
}, [user])
return [state.response, state.loading, state.error]
}
Specifically, I'm using this hook inside a form ponent, to fetch some data to use as options inside a select element.
However, I need to be able to let the user to add new options on the fly. To facilitate this, I've created a button next to the select element. If the user presses this button, a modal will pop up with another form that makes it possible create a new option. This new option is sent to the server via a post request and if successful the modal closes.
The problem I'm facing is that after the modal closes, I have no way of updating the initial data fetched with my custom data fetching hook, unless I refresh the page. Is there a way to make this happen somehow without triggering a page refresh?
My initial hunch was to use a callback function and pass it to the the useGetFetch
and bind it to the useEffect
hook. I could then pass it to the form in the modal and call the function after a successful submission, but this hasn't worked.
Another option I'm looking is the useCallback
hook, but I don't currently understand it well enough to know whether or not it could be helpful.
EDIT
Specifically what I did was create a trigger function outside the parent ponent:
const trigger = () => console.log("click")
Bound it to the fetch hook:
const useGetFetch(url, token, user, parser, trigger) => {
const [state, dispatch] = useReducer(fetchReducer, initialState)
useEffect (() => {
if(user){
fetch(...)
.then((data)=> data.json())
.then(dispatch(...)) // setting the state here
.catch((error) => dispatch(...)) // set error state
}
}, [user, trigger])
return [state.response, state.loading, state.error]
}
And passed it to the child ponent inside the parent ponent:
const trigger = () => console.log("click")
const Parent = () => {
// load a bunch of stuff
// ...
const { show, toggle } = useModal()
const [optionsData, Loading, Error] = useGetFetch(
optionsUrl,
token,
user,
parser,
trigger
)
// ...
return (
<div>
{// ...}
<button
onClick={(e) => {
e.preventDefault()
toggle()
}}
>
Add
</button>
<Modal show={show} toggle={toggle}>
<ModalForm
show={show}
toggle={toggle}
trigger={trigger}
></ModalForm>
</Modal>
{// ...}
<div>
)
}
Inside ModalForm
trigger is called after a successful post request has been performed. After closing the modal, the data is not updated. My guess was that calling trigger inside ModalForm
would have triggered useEffect
inside of the useGetFetch
but it doesn't seem to work like that.
- Okay as far as i understood the problem is that you want to refetch the data when the user closes the modal? am i right? – Anurag Hazra Commented Jun 24, 2020 at 13:07
- Yes you're right. – P4nd4b0b3r1n0 Commented Jun 24, 2020 at 13:16
4 Answers
Reset to default 4If if understood your question clearly i think what you are trying to do is force a refetch whenever user closes the modal.
You can do that by triggering a force rerender inside the useGetFetch
hook like below:
const useGetFetch(url, token, user, parser) => {
const [state, dispatch] = useReducer(fetchReducer, initialState)
// calling refetch will force a rerender on the hook
const [shouldRefetch, refetch] = useState({});
useEffect (() => {
if(user){
fetch(...)
.then((data)=> data.json())
.then(dispatch(...)) // setting the state here
.catch((error) => dispatch(...)) // set error state
}
}, [user, shouldRefetch]); // note the dep array
// returning the refetch functions so we can call the refetch() on modal close.
return [state.response, state.loading, state.error, refetch];
}
And thats it for the useGetFetch, now you will use the hook like so :-
const Parent = () => {
const { show, toggle } = useModal();
// notice the refetch method
const [optionsData, Loading, Error, refetch] = useGetFetch(
optionsUrl,
token,
user,
parser
);
return (
<div>
<button
onClick={e => {
e.preventDefault();
toggle();
}}
>
Add
</button>
<Modal show={show} toggle={toggle}>
<ModalForm
show={show}
toggle={toggle}
trigger={() => {
// probably onClose would be better name instead of `trigger`
// calling the refetch method with empty object, this will cause rerender
refetch({});
}}
></ModalForm>
</Modal>
</div>
);
};
I think you are missing ,
inside useEffect function thats why you getting X is not a function Error
useEffect (() => {
if(user){
fetch(...)
.then((data)=> data.json())
.then(dispatch(...)) // setting the state here
.catch((error) => dispatch(...)) // set error state
}
//ma here
},[user]);
I've implemented a solution by using a boolean but thought there must be a better way of doing this. The accepted solution of using an object is similar but it I do not like the exposed API or look of it refresh({})
or refresh(!resfreshSomething)
.
So instead I came up with the following solution:
const useGetFetch(url, token, user, parser) => {
const [state, dispatch] = useReducer(fetchReducer, initialState)
const [shouldRefetch, refetch] = useState({});
const refresh = () => refetch({});
// call upon useEffect (() => { ...
return [state.response, state.loading, state.error, refresh];
}
This way you can simple use refresh();
outside your hook.
import React from "react";
export const useFetch = ({ method, url, body }) => {
const [data, setData] = React.useState(null);
const [loading, setLoading] = React.useState(false);
const [error, setError] = React.useState(null);
const fetchAPI = async () => {
try {
setLoading(true);
const response = await axios({ url, method, data: body });
setData(response.data);
} catch (error) {
setError(error.response.data);
} finally {
setLoading(false);
}
};
React.useEffect(() => {
fetchAPI();
}, []);
return {
loading,
error,
data,
refetch: fetchAPI,
};
};
本文标签: javascriptRefreshing data fetched with a custom hook after closing a modalStack Overflow
版权声明:本文标题:javascript - Refreshing data fetched with a custom hook after closing a modal - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742115193a2421434.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论