简体   繁体   中英

Pass dropdown value from function to React.useEffect() on selection

Goal: I am trying to change the link inside the fetch() function with the value that comes from the dropdown.

Attempts:

1) I attempted passing the value to the function like GetAPILinks(Link_from_dropdown) and calling it in the onSelect function however I am getting an error stating: Invalid hook call. Hooks can only be called inside of the body of a function component Invalid hook call. Hooks can only be called inside of the body of a function component

2) I have also tried other methods of passing it by storing it in a variable inside GetAPILinks but resulted in errors.

I am starting to believe I am approaching this all wrong. Any advice or help would be great!

My Code:

This code will fetch the data from a hard coded link and renders a dropdown button that prints the selected values to the console.

import React from 'react';
import { DropdownButton, Dropdown} from 'react-bootstrap';

const GetAPILinks = () => {
  const [apiData, setApiData] = React.useState([]);
  React.useEffect(() => {
    fetch('https://Random_API/Link_From_Dropdown_Goes_Here')
      .then((response) => {
        return response.json();
      })
      .then((data) => {
        setApiData(data);
      });
  }, []);

  return (
    <DropdownButton id="dropdown-item-button" title="API Links" onSelect={function(evt){console.log(evt)}}>
        <Dropdown.Item as="button" eventKey='API_Link1'>Link 1</Dropdown.Item>
        <Dropdown.Item as="button" eventKey='API_Link2'>Link 2</Dropdown.Item>
        <Dropdown.Item as="button" eventKey='API_Link3'>Link 3</Dropdown.Item>
    </DropdownButton>          
  );
}

export default GetAPILinks;

You're pretty close here. You should track another state value for the fetch Url. Tracking it in a local variable, or calling the function directly won't trigger your component to render when the values change.

const [fetchUrl, setFetchUrl] = useState(initialValue);

in your onSelect drop down you can set the value of the fetchUrl using the setFetchUrl function that the useState hook provides.

Now all that is left is to tell your useEffect hook that it needs to execute whenever the fetchUrl state value changes. You should add fetchUrl to the deps array.

It might look something like this:

const GetAPILinks = () => {
  const [apiData, setApiData] = React.useState([]);
  const [fetchUrl, setFetchUrl] = React.useState('');
  React.useEffect(() => {
    if (fetchUrl) {
      fetch(fetchUrl)
        .then((response) => {
          return response.json();
        })
        .then((data) => {
          setApiData(data);
        });
    }
  }, [fetchUrl]);

  return (
    <DropdownButton id="dropdown-item-button" title="API Links" onSelect={(e)=>{setFetchUrl(e.target.eventKey)}}>
        <Dropdown.Item as="button" eventKey='API_Link1'>Link 1</Dropdown.Item>
        <Dropdown.Item as="button" eventKey='API_Link2'>Link 2</Dropdown.Item>
        <Dropdown.Item as="button" eventKey='API_Link3'>Link 3</Dropdown.Item>
    </DropdownButton>          
  );
}

const GetAPILinks = () => {

const [apiData, setApiData] = React.useState([]);
const [url, setUrl] = React.useState(null);
React.useEffect(() => {
 if (url) {
  fetch('https://${url}`)
  .then((response) => {
    return response.json();
  })
  .then((data) => {
    setApiData(data);
  }});
}, [url]);

return (
<DropdownButton id="dropdown-item-button" title="API Links" 
    onSelect={evt=>setUrl(evt.key)}>
    <Dropdown.Item as="button" eventKey='API_Link1'>Link 
        1
    </Dropdown.Item>
  </DropdownButton>          
 );
}

 export default GetAPILinks;

You should create another state for current link and add it to useEffect dependencies.

It should be something like that, I didn't test.

import React from 'react';
import { DropdownButton, Dropdown} from 'react-bootstrap';

const GetAPILinks = () => {
  const [apiData, setApiData] = React.useState([]);
  const [currentLink, setCurrentLink] = React.useState('');

  React.useEffect(() => {
    fetch(`https://Random_API/${currentLink}`)
      .then((response) => {
        return response.json();
      })
      .then((data) => {
        setApiData(data);
      });
  }, [currentLink]);

  return (
    <DropdownButton id="dropdown-item-button" title="API Links" onSelect={(e)=>{setCurrentLink(e.target.eventKey)}}>
        <Dropdown.Item as="button" eventKey='API_Link1'>Link 1</Dropdown.Item>
        <Dropdown.Item as="button" eventKey='API_Link2'>Link 2</Dropdown.Item>
        <Dropdown.Item as="button" eventKey='API_Link3'>Link 3</Dropdown.Item>
    </DropdownButton>          
  );
}

export default GetAPILinks;

Hope it helps.

Add another piece of state to track the selected dropdown value

const [query, setQuery] = useState();

And add query to the dependency array of the effect and only make the fetch request when query is truthy

React.useEffect(() => {
  query && fetch(`https://Random_API/${query}`)
    .then((response) => {
      return response.json();
    })
    .then((data) => {
      setApiData(data);
    });
}, [query]);

编辑 mystifying-nash-wtfrc

A cleaner solution may be to factor out the fetch logic to its own function, call that with the callback, and store only the result in state

const GetAPILinks = () => {
  const [apiData, setApiData] = useState([]);

  const fetchData = query => fetch(`https://Random_API/${query}`)
    .then((response) => {
      return response.json();
    })
    .then(setApiData(data));

  return (
    <DropdownButton id="dropdown-item-button" title="API Links" onSelect={fetchData}>
        <Dropdown.Item as="button" eventKey='API_Link1'>Link 1</Dropdown.Item>
        <Dropdown.Item as="button" eventKey='API_Link2'>Link 2</Dropdown.Item>
        <Dropdown.Item as="button" eventKey='API_Link3'>Link 3</Dropdown.Item>
    </DropdownButton>          
  );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM