0

I am trying to create a component that will search a REST API through an axios request, and then return a list of the results. Right now, I'm facing an issue where all I am getting when I search is 'undefined' and I have no clue why. Any and all suggestions would be amazing.

Users.js

import React, { Component } from 'react';
import axios from 'axios';
import { search } from './utils';
import Users from './UsersDelete';

class App extends Component {
  state = {
    users: null,
    loading: false,
    value: ''
  };

  search = async val => {
    this.setState({ loading: true });
    const res = await search(
      `https://zuul-stage.whatifops.com/v1/user/email/${val}`
    );
    const users = await res.data.results;

    this.setState({ users, loading: false });
  };

  onChangeHandler = async e => {
    this.search(e.target.value);
    this.setState({ value: e.target.value });
  };

  get renderUsers() {
    let users = <h1>There's no movies</h1>;
    if (this.state.movies) {
      users = <Users list={this.state.users} />;
    }

    return users;
  }

  render() {
    return (
      <div>
        <input
          value={this.state.value}
          onChange={e => this.onChangeHandler(e)}
          placeholder='Type something to search'
        />
        {this.renderUsers}
      </div>
    );
  }
}

export default App;

User.js

import React from 'react';
import { truncStr } from './utils';

const User = props => {
  const { id, email, phone } = props.item;

  return (
    <div className={classes.Container}>
      <div className={classes.VoteContainer}>
        <span className={classes.Vote}>{email}</span>
      </div>

      <div className={classes.Bottom}>
        <h3 className={classes.Title}>{truncStr(phone, 19)}</h3>
      </div>
    </div>
  );
};

export default User;

UsersDelete.js

import React from 'react';
import User from './User';

const Users = ({ list }) => {
  let cards = <h3>Loading...</h3>;

  if (list) {
    cards = list.map((m, i) => <User key={i} item={m} />);
  }

  return (
    <div>
      <div>{cards}</div>
    </div>
  );
};

export default Users;

utils.js

import axios from 'axios';

export const truncStr = (string, limit) => {
  return string.length > limit
    ? string
        .trim()
        .substring(0, limit - 3)
        .trim() + '...'
    : string;
};

const resources = {};

const makeRequestCreator = () => {
  let cancel;

  return async query => {
    if (cancel) {
      // Cancel the previous request before making a new request
      cancel.cancel();
    }
    // Create a new CancelToken
    cancel = axios.CancelToken.source();
    try {
      if (resources[query]) {
        // Return result if it exists
        return resources[query];
      }
      const res = await axios(query, { cancelToken: cancel.token });

      const result = res.data.results;
      // Store response
      resources[query] = result;

      return result;
    } catch (error) {
      if (axios.isCancel(error)) {
        // Handle if request was cancelled
        console.log('Request canceled', error.message);
      } else {
        // Handle usual errors
        console.log('Something went wrong: ', error.message);
      }
    }
};
};

export const search = makeRequestCreator();

**Update: This is the response info after I called console.log(res) after the search function enter image description here

Alyssa
  • 143
  • 3
  • 15
  • What is the value of `res`, after the `search` call? – maazadeeb Jan 28 '20 at 02:44
  • @MaazSyedAdeeb it's coming up as 'undefined' after the call, and console.log(res) is showing a correct 200 response, but ONLY with the FIRST letter that was typed in – Alyssa Jan 28 '20 at 02:47
  • Looks like you're looking for something like [this](https://stackoverflow.com/questions/4220126/run-javascript-function-when-user-finishes-typing-instead-of-on-key-up) and/or [this](https://stackoverflow.com/questions/42217121/searching-in-react-when-user-stops-typing) – maazadeeb Jan 28 '20 at 02:51
  • Not really. I'm looking more to just search a REST API with axios, and then I want that list to show the results – Alyssa Jan 28 '20 at 03:18
  • 1
    The first letter is going to the REST API because you call `search` in the onChange handler, and the onChange handler is triggered for every key that you type in. So, if you want to wait for some time before you make the call, you need to use the solutions in the links that I've provided to do so. – maazadeeb Jan 28 '20 at 03:59
  • what if i just wanted to make the call on a button click after the input is there? – Alyssa Jan 28 '20 at 04:14
  • Then just call the search function on the button's onClick handler. You already have the value of the input in `this.state.value`. – maazadeeb Jan 28 '20 at 04:30

1 Answers1

2

A few things wrong with your code:

  • There is no results property on the data returned from the REST API
  • You don't need to await on this line: const users = await res.data.results;
  • There is no movies property on your state

I created a codesandbox to test your solution, here is an updated version: https://codesandbox.io/s/async-browser-tz4p6

I have removed a few things from the User.js file that were not necessary (for my tests)

andre
  • 448
  • 1
  • 3
  • 8
  • this looks like a good solution, however i'm still getting an undefined response – Alyssa Jan 28 '20 at 04:08
  • if the string to be searched is empty, the result is an error, so the `catch` block is executed. I have updated it to return an empty array – andre Jan 28 '20 at 04:14
  • oh! so i see that it's kind of working now, I see what you did. however, it's only sending the first letter of the input to the Rest API. how could we fix this? – Alyssa Jan 28 '20 at 04:16
  • if this answers your question, please mark it as the answer. – andre Jan 28 '20 at 04:36