Pascal
Pascal

Reputation: 79

React - How to use higher-level useState in imported functions

The following code (with some parts of it cut out for the sake of brevity) is working:

function AddressInputList({
  isOpen,
  inputValue,
  highlightedIndex,
  getItemProps,
  getMenuProps
}: AutocompleteInputListProps) {
  const [items, setItems] = useState<MarkerPoint[]>([])
  const api = 'XXXX'
  const fetchURL = `https://api.opencagedata.com/geocode/v1/json?key=${api}&q=${inputValue}&limit=5&pretty=1`

  useEffect(() => {
    async function fetchData() {
      if (inputValue !== null && inputValue.length > 1) {
        try {
          const request = await axios.get(fetchURL)
          const items = request.data.results.map((res: any) => {
            return {
              lat: res.geometry.lat,
              lng: res.geometry.lng,
              address: res.formatted
            }
          })
          setItems(items)
        } catch (error) {
          console.error(error)
        }
      }
    }
    fetchData()
  }, [inputValue])

  return (/*Code cut out*/)
}

What I now would like to do is to refactor the code to make it more lean. So I will create a utility.ts-file in which I have the fetchData-function and I subsequently would like to import the fetchData-function into the initial AddressInputList-function:

utility.ts:

export async function fetchData(inputValue: string, fetchURL: string) {
  if (inputValue !== null && inputValue.length > 1) {
    try {
      const request = await axios.get(fetchURL)
      const items = request.data.results.map((res: any) => {
        return {
          lat: res.geometry.lat,
          lng: res.geometry.lng,
          address: res.formatted
        }
      })
      setItems(items)
    } catch (error) {
      console.error(error)
    }
  }
}

Now my problem here is that I don't know how to make the useState-hook setItems available in utility.ts. I read somewhere that this could be done with props but I'm not sure how this would look like. A short example would be highly appreciated!

Upvotes: 2

Views: 38

Answers (2)

Yannick Vermeulen
Yannick Vermeulen

Reputation: 148

I guess you could just pass setItems as a callback function, as a parameter to your fetchData function.

fetchData(inputValue: string, fetchURL: string, setItems) {
    ...
}

Upvotes: 1

Taras Danyliuk
Taras Danyliuk

Reputation: 256

Just create a custom hook that would fetch data for you. I wouldn't recommend to tie this hook to inputValue so much. Also that .map formatting does not feel universal too.

export function useFetchData(inputValue: string, fetchURL: string) {
  const [items,setItems] = useState([]);

  useEffect(() => {
    async function fetchData() {
      if (inputValue !== null && inputValue.length > 1) {
        try {
          const request = await axios.get(fetchURL)
          const items = request.data.results.map((res: any) => {
            return {
              lat: res.geometry.lat,
              lng: res.geometry.lng,
              address: res.formatted
            }
          })
          setItems(items)
        } catch (error) {
          console.error(error)
        }
      }
    }
  }, [inputValue]);

  return items;
}

After that you can use this custom hook like so

const items = useFetchData(inputValue, "/api/<endpoint>);

Upvotes: 2

Related Questions