Как лучше всего установить данные для компонента из API в React JS

У нас есть страница сведений о продукте, которая содержит несколько компонентов на одной странице.

Компонент продукта выглядит так:

class Product  extends Component {
  render() {
    return (
      <div>
        <Searchbar/>
        <Gallery/>
        <Video/>
        <Details/>
        <Contact/>
        <SimilarProd/>
        <OtherProd/>
      </div>
    );
  }
}

Здесь у нас есть 3 API для - Подробности - Аналогичный продукт - Другие продукты

Теперь из Detail API нам нужно установить данные для этих компонентов.

<Gallery/>
<Video/>
<Details/>
<Contact/>

В каком компоненте нам нужно сделать вызов API и как установить данные для других компонентов. Допустим, нам нужно присвоить значение a, b, c, d каждому компоненту.

componentWillMount(props) {
  fetch('/deatail.json').then(response => {
      if (response.ok) {
        return response.json();
      } else {
        throw new Error('Something went wrong ...');
      }
    })
    .then(data => this.setState({ data, isLoading: false }))
    .catch(error => this.setState({ error, isLoading: false }));
}

ИЛИ ЖЕ

Нужно ли нам создавать отдельный api для каждого компонента?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
0
1 010
4

Ответы 4

Поскольку это три разных компонента, вам нужно сделать вызов в компоненте, где встречаются все компоненты. И передайте состояние от родительского компонента дочерним компонентам. Если ваше приложение динамическое, вы должны использовать «Redux» или «MobX» для управления состоянием. Я лично вам советую использовать Redux

class ParentComponent extends React.PureComponent {

   constructor (props) {
     super(props);
     this.state = {
        gallery: '',
        similarPdts: '',
        otherPdts: ''
     }
   }


   componentWillMount () {
      //make api call and set data
   }

   render () {
      //render your all components
   }


}

Компонент Product - лучшее место для размещения вызова API, поскольку он является общим предком для всех компонентов, которым требуются эти данные.

Я бы рекомендовал вам переместить фактический вызов из компонента в общее место со всеми вызовами API.

В любом случае, вы ищете что-то вроде этого:

import React from "react";
import { render } from "react-dom";
import {
  SearchBar,
  Gallery,
  Video,
  Details,
  Contact,
  SimilarProd,
  OtherProd
} from "./components/components";

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

    // Set default values for state
    this.state = {
      data: {
        a: 1,
        b: 2,
        c: 3,
        d: 4
      },
      error: null,
      isLoading: true
    };
  }

  componentWillMount() {
    this.loadData();
  }

  loadData() {
    fetch('/detail.json')
      .then(response => {
        // if (response.ok) {
        //   return response.json();
        // } else {
        //   throw new Error('Something went wrong ...');
        // }
        return Promise.resolve({
          a: 5,
          b: 6,
          c: 7,
          d: 8
        });
      })
      .then(data => this.setState({ data, isLoading: false }))
      .catch(error => this.setState({ error, isLoading: false }));
  }

  render() {
    if (this.state.error) return <h1>Error</h1>;
    if (this.state.isLoading) return <h1>Loading</h1>;

    const data = this.state.data;
    return (
      <div>
        <SearchBar/>
        <Gallery a = {data.a} b = {data.b} c = {data.c} d = {data.d} />
        <Video a = {data.a} b = {data.b} c = {data.c} d = {data.d} />
        <Details a = {data.a} b = {data.b} c = {data.c} d = {data.d} />
        <Contact a = {data.a} b = {data.b} c = {data.c} d = {data.d} />
        <SimilarProd/>
        <OtherProd/>
      </div>
    );
  }
}

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

Рабочий пример здесь: https://codesandbox.io/s/ymj07k6jrv

Вызовы API будут в компоненте продукта. Учитывая ваши потребности в передовых методах, я хочу убедиться, что вы используете реализацию архитектуры FLUX для потока данных. Если нет, посетите phrontend

Вы должны отправлять вам вызовы API в componentWillMount (), имея в вашем состоянии индикатор загрузки, который будет отображать загрузчик до тех пор, пока данные не будут извлечены.

Каждый из ваших компонентов должен следить за состоянием своих соответствующих данных. Допустим, у вас есть такое состояние, как {loading: true, galleryData: {}, details: {}, simProducts: {}, otherProducts: {}}. При рендеринге компонент похожих продуктов должен отображаться, если он находит соответствующие данные в состоянии. Что вам нужно сделать, так это просто обновлять состояние всякий раз, когда вы получаете данные.

Вот фрагмент рабочего кода:

Компонент продукта:

    import React from 'react';
    import SampleStore from '/storepath/SampleStore';
     
    export default class ParentComponent extends React.Component {
    
       constructor (props) {
         super(props);
         this.state = {
         loading:true,
         }
       }
    
    
      componentWillMount () {
        //Bind Store or network callback function
        this.handleResponse = this.handleResponse
        //API call here.
      }

      handleResponse(response){
      // check Response Validity and update state
      // if you have multiple APIs so you can have a API request identifier that will tell you which data to expect.
      if (response.err){
       //retry or show error message
      }else{
       this.state.loading = false;
       //set data here in state either for similar products or other products and just call setState(this.state)
       this.state.similarProducts = response.data.simProds;
       this.setState(this.state);
      }
     }
    
       render () {
          return(
           <div>
           {this.state.loading} ? <LoaderComponent/> : 
            <div>
             <Searchbar/>
             <Gallery/>
             <Video/>
             <Details/>
             <Contact/>
             {this.state.similarProducts && <SimilarProd data = {this.state.similarProducts}/>}
             {this.state.otherProducts && <OtherProd data = {this.state.otherProducts}/>}
         </div>
         </div>
         );
    
      }
    }

Просто продолжайте устанавливать данные в состоянии, как только вы их получаете, и визуализируйте ваши компоненты, которые должны быть осведомлены о состоянии.

In which component we need to make a call to API and how to set data to other components.

Вызов API должен выполняться в компоненте продукта, как описано в других ответах. Теперь для настройки данных, учитывая, что вам нужно сделать 3 вызова API (Подробности, Аналогичный продукт, Другие продукты), вы можете выполнить приведенную ниже логику в componentDidMount() :

var apiRequest1 = fetch('/detail.json').then((response) => { 
        this.setState({detailData: response.json()})
        return response.json(); 
});
var apiRequest2 = fetch('/similarProduct.json').then((response) => { //The endpoint I am just faking it
    this.setState({similarProductData: response.json()}) 
    return response.json();
});
var apiRequest3 = fetch('/otherProduct.json').then((response) => { //Same here
    this.setState({otherProductData: response.json()}) 
    return response.json();
});

Promise.all([apiRequest1,apiRequest2, apiRequest3]).then((data) => {
    console.info(data) //It will be an array of response
    //You can set the state here too.    
});

Другой более короткий путь будет:

const urls = ['details.json', 'similarProducts.json', 'otherProducts.json'];

// separate function to make code more clear
const grabContent = url => fetch(url).then(res => res.json())

Promise.all(urls.map(grabContent)).then((response) => {
    this.setState({detailData: response[0]})
    this.setState({similarProductData: response[1]})
    this.setState({otherProductData: response[2]})
});

А затем в функции render () Product вы можете передать данные API как

class Product  extends Component {
    render() {
    return (
        <div>
        <Searchbar/>
        <Gallery/>
        <Video/>
        <Details details = {this.state.detailData}/>
        <Contact/>
        <SimilarProd similar = {this.state.similarProductData}/>
        <OtherProd other = {this.state.otherProductData}/>
        </div>
    );
    }
}

И в соответствующем компоненте вы можете получить доступ к данным как:

this.props.details //Considering in details component.

Другие вопросы по теме