2
votes

I have my custom useResults hook like this

import { useEffect, useState } from 'react';
import yelp from '../api/yelp';

export default () => {
  const [results, setResults] = useState([]);
  const [errorMessage, setErrorMessage] = useState('');

  const searchApi = async (searchTerm:string) => {
    console.log('Hi there!');
    try {
      const response = await yelp.get('/search', {
        params: {
          limit: 50,
          term: searchTerm,
          location: 'san jose'
        }
      });
      setResults(response.data.businesses);
    } catch (err) {
      setErrorMessage('Something went wrong');
    }
  };

  useEffect(() => {
    searchApi('pasta');
  }, []);

  return [searchApi, results, errorMessage];
};

in my Search screen I import my custom hook and do a destructuring like this

const [searchApi, errorMessage, results ] = useResults();

But I can't call my searchApi method from JSX code like below (I can call errorMessage and results).

<SearchBar term={term} onTermChange={setTerm} onTermSubmit={()=>searchApi(term)}/>

I'm getting this error

This expression is not callable. Not all constituents of type 'string | ((searchTerm: string) => Promise) | never[]' are callable. Type 'string' has no call signatures

How to pass the "searchApi" function to "onTermSubmit" prop in my "SearchBar" component ? as you can see "searchApi" is an async function

Below is my package.json

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "eject": "expo eject"
  },
  "dependencies": {
    "@react-native-community/masked-view": "^0.1.10",
    "@types/axios": "^0.14.0",
    "axios": "^0.21.1",
    "expo": "~40.0.0",
    "expo-status-bar": "~1.0.3",
    "react": "16.13.1",
    "react-dom": "16.13.1",
    "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz",
    "react-native-gesture-handler": "~1.8.0",
    "react-native-reanimated": "~1.13.0",
    "react-native-safe-area-context": "3.1.9",
    "react-native-screens": "~2.15.0",
    "react-native-web": "~0.13.12",
    "react-navigation": "^4.4.3",
    "react-navigation-stack": "^2.10.2"
  },
  "devDependencies": {
    "@babel/core": "~7.9.0",
    "@types/react": "~16.9.35",
    "@types/react-dom": "~16.9.8",
    "@types/react-native": "~0.63.2",
    "typescript": "~4.0.0"
  },
  "private": true
}

Below is my tsconfig.json

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "jsx": "react-native",
    "lib": ["dom", "esnext"],
    "moduleResolution": "node",
    "noEmit": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "strict": true
  }
}

enter image description here

2

2 Answers

7
votes

FYI, in order to keep elements in an array to keep position without allowing tsc infers thing you can set it as fixed by setting as const:

return [searchApi, results, errorMessage] as const;
1
votes

Because you are returning

 return [searchApi, results, errorMessage];

and not

 return { searchApi, results, errorMessage };

There is importance for the position of the destructed value, and not to the string key you named.

Therefore by

const [searchApi, errorMessage, results ] = useResults();

errorMessage and results are points on each other and not on themself