简体   繁体   English

React - Axios 始终承诺获取道具返回

[英]React - Axios to get props return always promise

I have a react application that renders from a main component, when this component is mounted I fetch some data using redux thunk and pass the response as a global state, in this main component there is a component that render a specific item of the array of data that redux passed as props, for this I filter the array data with the id parameter in the url that match, the problem is that when the page is reloaded this data is no longer available so the view of the specific item crash, so I am trying to create a ternary operator condition that check if the props array length is 0 then an axios request is done to the api to get the specific item using the parameter of the url but though I see the response in the console this does not pass as prop to the component that render the specific item just the promise is seen.我有一个从主要组件呈现的反应应用程序,当这个组件被安装时我使用 redux thunk 获取一些数据并将响应作为全局状态传递,在这个主要组件中有一个组件呈现数组的特定项目redux 作为 props 传递的数据,为此我用匹配的 url 中的 id 参数过滤数组数据,问题是当页面重新加载时这个数据不再可用所以特定项目的视图崩溃,所以我我正在尝试创建一个三元运算符条件来检查 props 数组长度是否为 0,然后向 api 发出 axios 请求以使用 url 的参数获取特定项目,但是尽管我在控制台中看到了响应,但这并没有通过作为呈现特定项目的组件的支柱,只看到承诺。

the main component is this:主要组成部分是这样的:

import React, { Component } from 'react';
import {Routes, Route, Navigate, useParams, useNavigate} from 'react-router-dom'; //Switch changed to routes Also redirect is changed to Navigate since version 6
import {connect} from 'react-redux';
import { useLocation } from 'react-router-dom';


import Header from './HeaderComponent';
import Home from './home-components/HomeComponent';

import Footer from './FooterComponent';

import Vitrina from './vitrina-components/VitrinaComponent';
import CarDetailComponent from './vitrina-components/CardetailComponent';
import {fetchCars, fetchOfertas} from '../redux/ActionCreators';
import axios from 'axios';
import { baseUrl } from '../shared/baseUrl';

// --------Hook to use withRouter from v5 in actual v6-----------------
export const withRouter = (Component) => {
  const Wrapper = (props) => {
    const history = useNavigate();
    const location = useLocation();
    const params = useParams();
    
    return (
      <Component
        history={history}
        location={location}
        params={params}
        {...props}
        />
    );
  };
  
  return Wrapper;
};


const mapStateToProps = (state) => {
    return{

        cars: state.cars
       
    }
}

const mapDispatchToProps = dispatch => ({
  //axios fetch data function
  fetchCars: () => { dispatch(fetchCars())}

});



class Main extends Component {

  componentDidMount() {
    //when mounted the data is fetched
    this.props.fetchCars(); 
  }
  
  render(){
  
    //this is the component where the specific item is rendered    
    const CarWithId = () => {

      let params = useParams();
      
      return(
          // here is the actual logic to pass the specific item to the component to render
          <CarDetailComponent car={this.props.cars.cars.filter((car) => car._id === params.carId)[0]}/>
        
      );
    };
    
  return (  
    
    <div>
      <Header/>  
      <Routes>
        <Route path = "/login" element = {<LoginComponent/>}/>
        <Route path="/home" element={<Home cars={this.props.cars}/>}/> 

        <Route exact path="/vitrina" element= {<Vitrina cars={this.props.cars} />} />  
        <Route path = "/vitrina/:carId" element={<CarWithId />} />

        <Route path="*"element={<Navigate to="/home" />} />
        {/* Instead of redirect the above is needed to redirect if there is no matched url*/}
      </Routes>
      
      <Footer location={this.props.location}/>
    </div>
  );
}
};



export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Main));

what I am trying right now in the CarWithId to pass the specific item when the page is reloaded is this我现在在 CarWithId 中尝试在重新加载页面时传递特定项目是这个

    const CarWithId = () => {
      let params = useParams();

      async function getCar(){
        let car;
        await axios.get(baseUrl+'cars/'+params.carId)
        .then((response) => {
            car = response.data
            console.log('response.data',response.data)
        })
        .catch((error) => {
            console.log(error)
        })
        return car;
      }
      
      return(

          <CarDetailComponent car={this.props.cars.cars.length===0 ?  getCar() :this.props.cars.cars.filter((car) => car._id === params.carId)[0]}/>
        
      );
    };

but i get this in the console when login the getCar() function但是我在登录 getCar() 函数时在控制台中得到了这个

响应 getCar()

how can i correctly do the axios request in order to pass the response.data as the car to the carDetailComponent, also in the inner console.log('response.data',response.data) of the function the response is as what i expect but for a reason in the car this is not passed as the prop我怎样才能正确地执行 axios 请求,以便将 response.data 作为汽车传递给 carDetailComponent,也在函数的内部console.log('response.data',response.data)中,响应与我一样期待,但出于汽车的原因,这没有作为道具通过

EDIT added the carDetailComponent编辑添加了 carDetailComponent

import React, {useState, useEffect} from 'react';
import {
        //Card, CardImg, CardText, CardBody, CardTitle,
         Breadcrumb,BreadcrumbItem} from 'reactstrap';
import {Link} from 'react-router-dom'

import { baseUrl } from '../../shared/baseUrl';
import { formatMoney } from '../../shared/utils';
import whatsappIcon from '../../static/assets/icons/whatsapp.svg';


const imgPath = baseUrl + "images/vehiculos/";
function RenderCar({car}){

  // hooks to manage the state of the component
  
  if (car != null){
      const message = `Hola, estoy interesado en el vehículo ${car.marca} ${car.linea} ${car.modelo}`;
     
    return(
        <div className="container">
          <div className="row mb-2">
            
            {/* < -- Col -- > */}
            <div className="col-12 col-md-9">
              <div className='container-fluid '>
                <div className='row'>

                  {/* < -- Col -- > */}
                  <div className='col-2'>
                    {/* here will be showed the miniatures in vertical when one is clicked will have a blue border*/}
                    {car.images.map((image, index) => {
                      return(
                        <div key={index} className='row vertical-center'>
                          {/* images must be responsive */}
                          <img src={imgPath +
                            car.marca + "_" + car.linea + "_" + car.modelo + "/" + image}
                            alt={car.marca + "_" + car.linea + "_" + car.modelo + "_" + index}
                            className= {`card side-column-images px-0 mb-2 ${currentImage === index ? "selected" : undefined}`} 
                            onClick={() => setCurrentImage(index)}
                            onMouseOver={() => setCurrentImage(index)}
                          />

                        </div>
                      );
                    })}


                  </div>

                  {/* < -- Col -- > */}
                  <div className='col-10'>
                    
                    <img 
                      className="card-img-top principal-image-vitrina mx-2" 
                      src={imgPath + car.marca + "_" + car.linea + "_" + car.modelo + "/" + car.images[currentImage]} 
                      alt={car.name}
                    />
             

                   
                  </div>

                </div>
              </div>
            </div>

            {/* < -- Col -- > */}           
             {/*car information  Marca, linea, modelo, precio*/}
            <div className="col-3 col-md-3 card pb-2">
              <div className="card-body">
                <p className="card-text text-muted responsive-text">{car.modelo} | {car.km} km</p>
                <h3 className="card-title responsive-title">{car.marca} {car.linea}</h3>
                
                
                <h2 className="card-text display-6">${formatMoney(car.price)}</h2>

                {/* buttons for buy and other to contact via whatsapp */}
                <div className="row">
                  <div className="col-12 col-md-6">
                    <button type="button" className="btn btn-primary btn-block">Comprar</button>
                  </div>
                  {/* use whatsapp.svg icon that is on static/assets/icons*/}
                  <div className="col-12 col-md-6">
                    {/* button will redirect to wppApi onClick*/}
                    <button type="button" className="btn btn-success btn-block" onClick={() => window.open(wppApi, "_blank")}>
                      <img src={whatsappIcon} alt="whatsapp" style={{height:20, width:20,fill:"white"}} className="whatsapp-icon"/>
                      Contactar
                    </button>
                  </div>
                </div>
              </div>
            </div>

          </div>
          {/* principal characterist rendered in a table, modelo, marca, linea, Tipo, km, cilindrake,transmision,direccion,combustible,color*/}
          <div className="row">
            <div className="col-12 col-md-9">
              <div className="">
                <div className="card-body">
                  <h4 className="card-title">Caracteristicas Principales</h4>
                  <table className="table table-striped">
                    <tbody>
                      <tr>
                        <th scope="row">Modelo</th>
                        <td>{car.modelo}</td>
                      </tr>
                      <tr>
                        <th scope="row">Marca</th>
                        <td>{car.marca}</td>
                      </tr>
                      <tr>
                        <th scope="row">Linea</th>
                        <td>{car.linea}</td>
                      </tr>
                      <tr>
                        <th scope="row">Tipo</th>
                        <td>{car.Tipo}</td>
                      </tr>
                      <tr>
                        <th scope="row">Kilometraje</th>
                        <td>{car.km}</td>
                      </tr>
                      <tr>
                        <th scope="row">Cilindraje</th>
                        <td>{car.cilindraje}</td>
                      </tr>
                      <tr>
                        <th scope="row">Transmision</th>
                        <td>{car.transmision}</td>
                      </tr>
                      <tr>
                        <th scope="row">Direccion</th>
                        <td>{car.direccion}</td>
                      </tr>
                      <tr>
                        <th scope="row">Combustible</th>
                        <td>{car.combustible}</td>
                      </tr>
                      <tr>  
                        <th scope="row">Color</th>
                        <td>{car.color}</td>
                      </tr>
                    </tbody>
                  </table>
                </div>
              </div>
            </div>
          </div>
        </div>
    );
  }
  else{
    return(
      // redirects user to /vitrina route
      <div>
        <h3>No se encontro el carro</h3>
      </div>


      );
        }
}


const CarDetailComponents = (props)=> {
    
      return (
        <div className="container">
          <div className="row">
            <Breadcrumb>
                <BreadcrumbItem><Link to="/vitrina">vitrina</Link></BreadcrumbItem>
                <BreadcrumbItem active>{props.car.marca} {props.car.linea}</BreadcrumbItem>
            </Breadcrumb>
            <div className="col-12">
                <h3>{props.car.marca} {props.car.linea}</h3>
                <hr/>
            </div>                
          </div>

          <div className="row">     
            <RenderCar car={props.car}/>               
          </div>
        </div>
      );

}


export default CarDetailComponents;



  1. Remove the getCar function from your CarWithId componentCarWithId组件中删除getCar函数

  2. You can leave the render of the car details component like this您可以像这样留下汽车细节组件的渲染

<CarDetailComponent car={this.props.cars.cars.length===0 ? null :this.props.cars.cars.filter((car) => car._id === params.carId)[0]}/>
  1. Then update your CarDetailComponents to this然后将您的 CarDetailComponents 更新为此

const CarDetailComponents = (props)=> {
    const [car, setCar] = useState(props.car)
    let params = useParams();

    async function getCar(){
      await axios.get(baseUrl+'cars/'+params.carId)
      .then((response) => {         
          setCar(response.data)
          console.log('response.data',response.data)
      })
      .catch((error) => {
          console.log(error)
      })
    }

    useEffect(() => {
        if(!props.car){
            getCar()
        }
    },[props.car])


    
    return (
      <div className="container">
        <div className="row">
          <Breadcrumb>
              <BreadcrumbItem><Link to="/vitrina">vitrina</Link></BreadcrumbItem>
              <BreadcrumbItem active>{car?.marca} {car?.linea}</BreadcrumbItem>
          </Breadcrumb>
          <div className="col-12">
              <h3>{car?.marca} {car?.linea}</h3>
              <hr/>
          </div>                
        </div>

        <div className="row">    
        {car &&  <RenderCar car={car}/>   } 
              
        </div>
      </div>
    );

}

This will check if car is assigned, if not it will fetch the car这将检查汽车是否已分配,如果没有,它将取车

why you also using await and then为什么你还使用 await 然后

how about?怎么样?

async function getCar() {
    try {
        const response = await axios.get(baseUrl + 'cars/' + params.carId);
        console.log("response.data", response.data)
        return response.data;
    } catch (err) {
        console.error(err)
    }
}

useEffect(() => {
    (async () => {
        const car = await getCar()
        setCar(car)
    })();
}, [])

<CarDetailComponent car={car} />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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