3

I'm using material-ui with a react functional component and using its Autocomplete component. I customized it and whenever I change the text in input field, I expect the component to render new search result.

callAPI("xyz")

I'm calling the API in the action and using the xyz parameter, I'm calling the dispatch method from this functional component.

Problem here is, when the component makes the call, it is supposed to wait for the API response and then render the result, but it gets an unresolved promise, so it fails rendering.

<Paper square>
    {callAPI("xyz").results.map(
        result => console.log(result);
    )}
</Paper>

as results are a unresolved promise, it will fail to map. I need some way to call the map only once data is available, or show some text before data is there and then change once data is fetched.

Any suggestions to correct this code will be very helpful.

EDIT:

function IntegrationDownshift() {
    return (
        <div>
            <Downshift id="downshift-simple">
                {({
                    getInputProps,
                    getItemProps,
                    getMenuProps,
                    highlightedIndex,
                    inputValue,
                    isOpen,
                    selectedItem
                }) => (
                    <div>
                        {renderInput({
                            fullWidth: true,
                            InputProps: getInputProps({
                                placeholder: "Search users with id"
                            })
                        })}

                        <div {...getMenuProps()}>
                            {isOpen ?
                                 <Paper square>
                                {callAPI(inputValue).users.map(
                                    (suggestion, index) =>
                                        renderSuggestion({
                                            suggestion,
                                            index,
                                            itemProps: getItemProps({
                                                item:
                                                    suggestion.userName
                                            }),
                                            highlightedIndex,
                                            selectedItem
                                        })
                                )}
                            </Paper>  
                             : null}
                        </div>
                    </div>
                )}
            </Downshift>
        </div>
    );
}
beta programmers
  • 261
  • 1
  • 4
  • 17
  • Dispatch an action for triggering loader or some text that the data is loading, once it get resolved dispatch the action for turning of the loader and setting the data. In your jsx you can write a ternary check if loader is true render the loader component else render the data – DILEEP THOMAS Jun 02 '19 at 18:16
  • @DILEEPTHOMAS Can you please provide any psuedo code or sample for your example please – beta programmers Jun 02 '19 at 18:26
  • can you provide some more code, i think paper is a customized component. So on change you will be calling a props and the dispatch is done in the parent component – DILEEP THOMAS Jun 02 '19 at 18:29
  • @DILEEPTHOMAS added additional code for reference, you can see the callAPI method is taking inputValue and returns the Object with users. I want to apply map on that and call another render. But when it loads initially, the renders without the data, as the promise is still unresolved, it fails with map. – beta programmers Jun 02 '19 at 18:41

2 Answers2

4

React 16.8 introduces Hooks:

Hooks are functions that let you “hook into” React state and lifecycle features from function components.

so you have useState() which you can declare a state variable with an empty array and call your API in the useEffect() to populate the state when you get the response from the API:

function App() {

  const [data, setData] = useState([]);

  useEffect(() => {
    callAPI("xyz").then(result => {
      setData(result);
    })  
  }, []);

  if(!data.length) return (<span>loading...</span>);

  return (
    <Paper square>
        {data.map(
            result => console.log(result);
        )}
    </Paper>
  );
}

More about hooks: https://reactjs.org/docs/hooks-intro.html.

Fraction
  • 6,401
  • 3
  • 15
  • 34
-1

Easiest way to handle this is with a ternanry expression And also its best practice to call your API request in a lifecycle method and then save the result in local state.

componentDidMount() {
    callAPI("xyz").results.map(
        result => this.setState(result);

}

<Paper square>
    {this.state.results ?
      this.state.results.map(
        result => console.log(result);
      : <p> Loading... </p>
    )}
</Paper>
iqbal125
  • 996
  • 1
  • 8
  • 13
  • But as I said it is a stateless functional component, so I can't use lifecycle methods and also localstate – beta programmers Jun 02 '19 at 18:18
  • You are making an API request here, why would you not make it a stateful component? – iqbal125 Jun 02 '19 at 19:21
  • 1
    Though stateless components are for rendering purpose, as per my minimal knowledge, there is no necessity for it to be stateful if it makes an API cal, unless it maintains the state by storing the API data for further reference. I'm ready to get corrected if I'm wrong. Thanks – beta programmers Jun 03 '19 at 18:52