Reputation: 65
I have a React stateless function component (SFC). I want a user to click a button and onclick a http call will be made from the SFC and when the response is received, I want to open a modal. Is it something achievable using SFC? Or do I need to keep a stateful component?
This is my code which makes the http call on load and then onClick opens the modal. But I want both the things to happen in sequence on the onClick event.
//HTTP CALL FUNCTION
function httpListCall(url) {
const [list, setData] = React.useState(null);
const [error, setError] = React.useState(null);
React.useEffect(() => {
axios
.get(url)
.then(function (response) {
setData(response.data.ResultList);
})
.catch(function (error) {
setError(error);
})
}, []);
return { list, error };
};
//SFC
const ListContainer = () => {
const { list, error } = httpListCall("/list.json"); //THIS IS ON LOAD NOW - I WANT TO CALL IT onClick
const [modalShow, setModalShow] = React.useState(false);
return(
<React.Fragment>
<div>
<button onClick={() => setModalShow(true)}/> //WANT TO MAKE API CALL HERE AND THEN OPEN THE MODAL
</div>
<ModalWidget show={modalShow} list={advisorList} error={error} onHide={() => setModalShow(false)}/>
</React.Fragment>
)
}
export default ListContainer;
ReactDOM.render(<ListContainer/>, document.getElementById("app"));
I have tried to make the http call from a function but it gives me an error: "Invalid hook call. Hooks can only be called inside of the body of a function component."
Upvotes: 1
Views: 3051
Reputation: 1576
SOLUTION (updated):
You have to follow custom hooks implementation requirement as I have mentioned in comment under your question - have to use name "use" in front of your custom hook function name and update useEffect dependencies.
function useHttpListCall(url) {
const [list, setData] = React.useState(null);
const [error, setError] = React.useState(null);
React.useEffect(() => {
axios
.get(url)
.then(function(response) {
setData(response.data);
})
.catch(function(error) {
setError(error);
});
}, [url]);
return { list, error };
}
And update your functional component to use your custom Hook like this.
const ListContainer = () => {
const [modalShow, setModalShow] = React.useState(false);
const [endpoint, setEndpoint] = React.useState(null);
const { list } = useHttpListCall(endpoint);
const handleClick = () => {
setModalShow(true);
setEndpoint("https://api.github.com/users?since=135");
};
return (
<React.Fragment>
<div>
<button onClick={handleClick}>Show modal of Github users</button>
</div>
{modalShow && list && (
<div>
{list.map(user => {
return <div key={user.id}>{user.login}</div>;
})}
</div>
)}
</React.Fragment>
);
};
I didn't implement modal as you did not provide the code for this component.
Fully working code is available here (for you to use as a reference): https://codesandbox.io/s/simple-custom-hook-n6ysw
Upvotes: 2
Reputation: 1
You cant use the new react hooks (useState, useEffect etc.) in a "normal" function, it has to be a function component.
You can put the hooks inside the component scope and keep the axios request in a seperate function.
Upvotes: 0