1

I have an API get request that does a search in a database and displays the information in a table. Currently I have a componentDidMount() that ruins a GET request and sets candidate with an array of data. When I run searchUpdate this will change the state candidate with data the searched data. The function successfully changes and updates the table with the searched information. The issue I am having trouble with is when the search doesn't find anything it sets candidate to {}, resulting in an error TypeError: this.state.candidate.map is not a function. Is there a way that I can work around this?

Code:

componentDidMount() {
    const access_token = JSON.parse(localStorage["appState"]).user.access_token;
    console.log("Access token = " + access_token);
    const config = {
      headers: {
        Authorization: "Bearer " + access_token,
      },
    };
    axios
      .get(
        "https://api/v1/candidate/list/lead/new lead?page=1",
        config
      )

      .then((response) => {
        console.log(response.data);
        this.setState({ candidate: response.data.data });
      })
      .catch((error) => {
        if (error.response) {
          // The request was made and the server responded with a status code
          // that falls out of the range of 2xx
          console.log(error.response.data);
          console.log(error.response.status);
          console.log(error.response.headers);
        } else if (error.request) {
          // The request was made but no response was received
          // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
          // http.ClientRequest in node.js
          console.log(error.request);
        } else {
          // Something happened in setting up the request that triggered an Error
          console.log("Error", error.message);
        }
        console.log(error.config);
      });
}

searchUpdate = (search) => {
    const access_token = JSON.parse(localStorage["appState"]).user.access_token;
    // console.log('Access token = ' + access_token);
    // Hard code token for the time being

    this.setState({ ...this.state, search: search });
    console.log(search);

    const config = {
      headers: {
        Authorization: "Bearer " + access_token,
      },
    };
    axios
      .get(
        "https://api/v1/candidate/search?q=" + search,
        config
      )

      .then((response) => {
        console.log(response.data);
        this.setState({ candidate: response.data });
      })
      .catch((error) => {
        if (error.response) {
          // The request was made and the server responded with a status code
          // that falls out of the range of 2xx
          console.log(error.response.data);
          console.log(error.response.status);
          console.log(error.response.headers);
        } else if (error.request) {
          // The request was made but no response was received
          // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
          // http.ClientRequest in node.js
          console.log(error.request);
        } else {
          // Something happened in setting up the request that triggered an Error
          console.log("Error", error.message);
        }
        console.log(error.config);
      });
  };

render() {
    if (this.state.candidate_counts === undefined) {
      return null;
    }

    const dataTable = this.state.candidate.map((item) => {
      return {
        id: item.id,
        name: item.name,
        current_company_name: item.current_company_name,
        job: item.job_title,
        owner: item.owner.name,
        updated: new Date(item.updated_at).toLocaleString(),
        email: item.email,
        phone: item.phone,
        is_active: item.is_active,
        is_snoozed: item.is_snoozed,
      };
    });


     return (
        <div className="candidate-list-container">
            <DataTable
              theme="solarized"
              customStyles={customStyles}
              noHeader={true}
              fixedHeader={true}
              columns={columns}
              data={dataTable}
              onRowClicked={this.handleChange}
              pagination={false}
              responsive={true}
            />
          </div>
Michael Lee
  • 327
  • 2
  • 5
  • 18

1 Answers1

1

I'd strongly recommend making sure that the API has a consistent response type. This means that if /v1/candidates?age=20 returns an array of Candidates with age 20, then the API should always respond with an array.

If you can't control the API's design, then you can duck-type:

if (this.state.candidate.map) {
  // you know you can (probably) use .map()
}

Another case is that you could check if candidate is {}. You can't do this.state.candidate === {} because this compares the reference. This is how you should check for an empty object specifically: https://stackoverflow.com/a/32108184/1231844.

OFRBG
  • 1,653
  • 14
  • 28
  • It has 2 response types: (1) where there is no content (2) where there is content – Michael Lee Aug 19 '20 at 23:37
  • That should, ideally, be handled with HTTP response statuses, such as No Content. – OFRBG Aug 19 '20 at 23:37
  • @MichaelLee it works, but I'd strongly suggest fixing this on the API side. The larger the project gets, the harder it is to handle edge cases. – OFRBG Aug 20 '20 at 01:25
  • Sorry i forgot to mention it does use HTTP resonses like 200 for Content and 204 for No Content. In that case what would I do differently? – Michael Lee Aug 20 '20 at 16:03