1

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."

2
  • useState and useEffect can be used only in component, you try to call them outside the scope of component. With react 16.8 hooks you can have "state" in functional component, so you don't need to convert to react class component. Commented Jul 25, 2019 at 15:19
  • If httpListCall is used as custom Hook, then add use in front of custom Hook name const { list, error } = useHttpListCall("/list.json") Commented Jul 25, 2019 at 15:22

2 Answers 2

2

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

Sign up to request clarification or add additional context in comments.

2 Comments

Updated solution to meet your requirement on loading data after button is clicked not on component render.
Okay. This looks exactly what I am trying to achieve. And regarding the Modal, it is a bootstrap modal. But it should work fine. Let me try it and confirm.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.