Reputation: 899
I have created a custom Hook which fetches data from the server, sends dispatch to the store and returns data. It is usable if I want to list all comments in my app, however, I wanted to reuse it in the component where I need to fetch all comment replies, and that should happen only when certain button is clicked.
This is the hook down below.
import { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
const useFetch = (url, options, actionType, dataType) => {
const [response, setResponse] = useState([]);
const dispatch = useDispatch();
useEffect(() => {
(async () => {
const res = await fetch(url);
const json = await res.json();
setResponse(json);
})();
}, []);
useEffect(() => {
dispatch({ payload: response, type: actionType });
}, [response]);
const data = useSelector(state => state[dataType]);
return data;
};
export default useFetch;
Inside of my component I need to fetch replies when a button is clicked
const ParentComment = ({ comment }) => {
const handleShowMoreReplies = (e) => {
e.preventDefault();
}
let replies = useFetch(
`/api/comment_replies?comment_id=${comment.id}`,
null,
"REPLIES_RECEIVED",
"replies"
);
return (
<div>
<Comment comment={comment} />
<div className="replies">
{replies.map(reply => (
<Comment key={reply.id} comment={reply} />
))}
<a href="#" className="show_more" onClick={handleShowMoreReplies}>
Show More Replies ({comment.replies_count - 1})
</a>
</div>
</div>
);
};
If I put useFetch
call inside of the handler I hget an error that Hooks can't be called there, but I need to call it only when the button is clicked so I don't know if there is a way to implement that.
Upvotes: 1
Views: 2756
Reputation: 181
I think you have subtle problems in your useFetch hook
1.your useEffect is having dep of ${url} and ${actionType } which you need to define.
2.In order to call this hook by clicking the button, you need to expose the setUrl as follows
const useFetch = ( initialUrl, options, actionType, dataType) => {
const [url, setUrl ] = useState(initialUrl);
const dispatch = useDispatch();
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch(url);
const data = await res.json();
dispatch({ payload: data, type: actionType });
} catch (error) {
console.log(error);
}
};
fetchData();
}, [url, actionType]);
const data = useSelector(state => state[dataType]);
return [ data, setUrl ];
};
export default useFetch;
Then when you are trying to use this hook, you can
const [data, fetchUrl] = useFetch(
`/api/comment_replies?comment_id=${comment.id}`,
null,
"REPLIES_RECEIVED",
"replies"
);
Then every time you have a button you can simply call
fetchUrl(${yourUrl}).
your hook will receive the new URL, which is the dep of your hook and rerender it.
Here is an related article https://www.robinwieruch.de/react-hooks-fetch-data
Upvotes: 1