简体   繁体   中英

How do I only render one result in a separate component using axios in React?

Edit//

I suppose my question isn't so clear. I'm trying to get one park returned when my url points to http://localhost:1233/details/ '${parkcode}'. I've defined the param for the url in my results.js file. But I'm having trouble in defining the this.setState in my details.js to render just one result of the park based on the id which also happens to be the park code.

I'm new to React (and possibly to JavaScript, I don't know anymore). I am following a tutorial - instead of using an npm package for an API I decided to branch out and use axios.get() to fetch data from an API. I am able to render the results from a component into the browser, however after adding on reach-router (I assume it's similar to React Router), I am having troubles rendering just one result of my API call as the page I am attempting to build is supposed to only show ONE result based on the ID I have defined.

In my main file, which is Results.js here, I am able to get the data with no problem and include them in my file using JSX and render them. I'm attempting to use the same logic as I did in that page in my Details.js page (which is the page that is supposed to show only one result to the ID in the route).

How I'm using axios in Results.js

componentDidMount() {
    axios
      .get(
        "https://developer.nps.gov/api/v1/parks?stateCode=wa&fields=images&api_key=" +
          `${nps}`
      )

      // https://css-tricks.com/using-data-in-react-with-the-fetch-api-and-axios/
      .then(res =>
        res.data.data.map(park => ({
          description: `${park.description}`,
          fullname: `${park.fullName}`,
          states: `${park.states}`,
          parkcode: `${park.parkCode}`,
          image: `${park.images[0] ? park.images[0].url : "No Image"}`,
          designation: `${park.designation}`
        }))
      )
      .then(parks => {
        this.setState({
          parks
        });
        console.log(parks);
      });
  }

How I'm attempting to use the same logic in Details.js

It's not recognizing park.name even though I did the API call. However, if I hard code park[0].name it works. I have no idea what I'm doing wrong here. It might be an obvious problem but help me.

class Details extends React.Component {
  constructor (props) {
    super(props);

    this.state = {
      loading: true,
    }
  }

  componentDidMount() {
    axios
      .get(
        "https://developer.nps.gov/api/v1/parks?stateCode=wa&fields=images&api_key=" +
          `${nps}`, 
          { id: this.props.id }

      ).then(res => {
        const park = res.data.data.map(park => ({
          description: `${park.description}`,
          fullname: `${park.fullName}`,
          states: `${park.states}`,
          parkcode: `${park.parkCode}`,
          image: `${park.images[0] ? park.images[0].url : "No Image"}`,
          designation: `${park.designation}`
        }))

        console.log(park.name);

        this.setState({
          name: park.name;
          loading: false
        })
      }).catch(err => {
        this.setState({error: err});
      })
  }

I'm expecting the page to recognize the id as defined in the GET request along with the axios, and render the park details in relation to the id. But now, it's doing none of it and I've been stuck on this for forever :(

I believe this is the part you are getting wrong

const parks = res.data.data.map(park => ({
  description: `${park.description}`,
  fullname: `${park.fullName}`,
  states: `${park.states}`,
  parkcode: `${park.parkCode}`,
  image: `${park.images[0] ? park.images[0].url : "No Image"}`,
  designation: `${park.designation}`
}))

console.log(parks) // this should display your array of all parks

this.setState({
  parks,
  loading: false
})

displayParks(parks) {
 const allParks = parks.map((park, index) => {
   return <div key={park.parkCode}>{park.fullname}<div>
 })
}


render() {
const { parks } = this.state;

const displayParks = parks && parks.length > 0 ? this.displayParks(parks) : <div>Loading parks</div>
  return (
      <div>{ displayParks }</div>
    );
  }

When you do a .map on an array you are basically creating another array and that is what is returned to your park variable.

So in your render method, you can then loop over every item in parks

You can try this in .then()

let park = res.data.data.map(park => ({
    description: `${park.description}`,
    fullname:    `${park.fullName}`,
    states:      `${park.states}`,
    parkcode:    `${park.parkCode}`,
    image:       `${park.images[0] ? park.images[0].url : "No Image"}`,
    designation: `${park.designation}`
}))
park = park[0]; // convert arrays of parks to single park
console.log(park.fullname); // now you can use `park.fullname`

or this

const park = {
    description: `${res.data.data[0].description}`,
    fullname:    `${res.data.data[0].fullName}`,
    states:      `${res.data.data[0].states}`,
    parkcode:    `${res.data.data[0].parkCode}`,
    image:       `${res.data.data[0].images[0] ? park.images[0].url : "No Image"}`,
    designation: `${res.data.data[0].designation}`
}
console.log(park.fullname); // now you can use `park.fullname`

otherwise do it in API

I think you can first set a state for your responses and then try to show them

same this :

state = {
  result: []
}

componentDidMount() {
  axios
    .get("https://developer.nps.gov/api/v1/parks?stateCode=wa&fields=images&api_key=" +`${nps}`).then((res) => {
      this.setState({result: res.data.data})
  })
}

render(){
  const result = this.state.result.map((el, index) => {
    return(
      //data
    )
  })
  return(
     <div>
       {result}
     </div>
  )
}

There are some unnecessary parts in your code. You don't need to construct your data as you do in your setState part. You are getting park list and it is already a structured data. So, just set your state with the data you get back.

After that, you can map over this data and render the parks with links for React Router. You can use parkCode as your URL param for Link . In Details component you can extract this parkCode and make a new request for park details, then set this to your state.

I'm providing an example.

index.js

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Results from "./Results";
import Details from "./Details";

const Routes = () => (
  <Router>
    <Switch>
      <Route exact path="/" component={Results} />
      <Route path="/details/:parkCode" component={Details} />
    </Switch>
  </Router>
);

ReactDOM.render(<Routes />, document.getElementById("root"));

Results

import React from "react";
import axios from "axios";
import { Link } from "react-router-dom";

class Results extends React.Component {
  state = {
    parks: [],
    loading: true,
  };

  componentDidMount() {
    axios(
      "https://developer.nps.gov/api/v1/parks?stateCode=wa&fields=images&api_key=LbqZVj21QMimfJyAHbPAWabFaBmfaTZtseq5Yc6t"
    ).then(res => this.setState({ parks: res.data.data, loading: false }));
  }

  renderParks = () =>
    this.state.parks.map(park => (
      <Link to={`/details/${park.parkCode}`} key={park.parkCode}>
        <div>{park.fullName}</div>
      </Link>
    ));

  render() {
    return (
      <div>{this.state.loading ? <p>Loading...</p> : this.renderParks()}</div>
    );
  }
}

export default Results;

Details

import React from "react";
import axios from "axios";

class Details extends React.Component {
  state = { park: "", loading: true };

  componentDidMount() {
    const { match } = this.props;
    axios(
      `https://developer.nps.gov/api/v1/parks?parkCode=${match.params.parkCode}&api_key=${nps}`
    ).then(res => this.setState({ park: res.data.data[0], loading: false }));
  }

  render() {
    return (
      <div>
        {this.state.loading ? <p>Loading...</p> : this.state.park.description}
      </div>
    );
  }
}

export default Details;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM