Search code examples
javascriptreactjsrestreact-hooksuse-effect

How do I re-fire or get useEffect to update after url parameter change to show a different API response


Hello I'll preface this by saying that I am pretty new to React and coding in general. I am currently going through the React Doc and learning. So sorry if this is trivial.

I am having an issue code here : https://pastebin.com/rkwS1x66 where I am trying to update a table based on a user clicking a button. I'm confident that my logic is solid up until the actual render. My click handling function works fine and on toggle it can display the url change through an alert(). The problem is that although the URL variable changes, the table does not re-render. I want the table to essentially re-render and show the different API call. Basically, it should show either the SWAP api or Pokemon api rendered in the table dynamically based on the button click.

The link contains my condensed code. My project contains more code but I thought this would suffice for the issue at hand.

function HeaderSection() {
 
  let baseUrl = "https://swapi.dev/api/people";
  const [data, setData] = useState([]);
  const [currentStatus , setStatus] = useState(false);
 
  let urlToggle = false;
 
  function urlChange(){
    urlToggle = !urlToggle;
    if(urlToggle)
    {
      baseUrl = "https://swapi.dev/api/people";
    }
    else
    {
      baseUrl = "https://pokeapi.co/api/v2/berry";
    }
  }
 
  
 
  useEffect(()=>{
    fetch(baseUrl)
    .then((response) =>{
      if(!response.ok)
      {
        return Promise.reject( new Error("Response Error!"));
      }
      else
      {
        return response.json();
      }
    })
    .catch ( (err) =>{
      console.log(err);
    })
    .then((json) => {
      try{
        setData(json.results);
        setStatus(true);
      }
      catch
      {
        return Promise.reject(new Error(`State Error!: Data: ${data} , Connection:${currentStatus}`));
      }
    })
    .catch((err) =>{
      console.log(err);
    })  
  },[baseUrl]);
 
  return (
    <div className='gio-main'>
     
      <div className='gio-container-3'>
       <h1>API Switch</h1>
       <h4>Endpoint request using vanilla JS displayed in custom table</h4>
       <p>You can switch between endpoints using this button!</p>
       <button onClick={urlChange}>Change API</button>
       {!currentStatus ?  <h2>Loading... </h2> : <Table data={data}/>}
      </div>
    </div>
  );
}
 
export default HeaderSection;


Solution

  • The reason why your useEffect hook isn't triggering on baseUrl and changes the value of data as you expect is that baseUrl isn't a state.

    The second argument, the list of the useEffect expect states, and will cause the useEffect to ttriger on state change, so using a "normal" variable will not cause the hook to trigger.

    To fix it simply change baseUrl to a useState. In your code:

    // change #1
    const [baseUrl, setBaseUrl] = useState("https://swapi.dev/api/people");
    
    //change #2
      function urlChange(){
        urlToggle = !urlToggle;
        if(urlToggle)
        {
          setBaseUrl("https://swapi.dev/api/people");
        }
        else
        {
          setBaseUrl("https://pokeapi.co/api/v2/berry");
        }
      }
    

    And now when the baseUrl changes the useEffect hook will retrigger.

    useEffect docs - look at the "note" part