У нас есть страница сведений о продукте, которая содержит несколько компонентов на одной странице.
Компонент продукта выглядит так:
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 для каждого компонента?





Поскольку это три разных компонента, вам нужно сделать вызов в компоненте, где встречаются все компоненты. И передайте состояние от родительского компонента дочерним компонентам. Если ваше приложение динамическое, вы должны использовать «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.