【问题标题】:What is best approach to set data to component from API in React JS在 React JS 中从 API 向组件设置数据的最佳方法是什么
【发布时间】:2018-03-11 08:13:33
【问题描述】:

我们的产品详情页面在单个页面中包含多个组件。

产品组件如下所示:

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 吗?

【问题讨论】:

    标签: reactjs components


    【解决方案1】:

    由于它是三个不同的组件,因此您需要在所有组件相遇的组件中进行调用。并将状态从父组件传递给子组件。如果您的应用是动态的,那么您应该使用“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
       }
    
    
    }
    

    【讨论】:

      【解决方案2】:

      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

      【讨论】:

        【解决方案3】:

        您的 API 调用将在产品组件中。为了满足您对最佳实践的需求,我想确保您使用 FLUX 架构的实现来进行数据流。如果没有,请访问phrontend

        您应该在 componentWillMount() 中向您发送 API 调用,让您的状态有一个加载指示器,该指示器将呈现一个加载器,直到未获取数据。

        您的每个组件都应该关注各自数据的状态。假设您的状态类似于 {loading:true, galleryData:{}, details:{}, simProducts:{}, otherProducts:{}}。在渲染类似产品组件时,如果它在状态中找到相应的数据,它应该渲染。您要做的就是在收到数据时更新状态。

        这里是工作代码sn-p:

        产品组件:

            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>
                 );
            
              }
            }
        

        只要在收到数据后立即将数据设置为状态,并且渲染组件应该是状态感知的。

        【讨论】:

          【解决方案4】:

          我们需要在哪个组件中调用API以及如何设置数据 到其他组件。

          API 调用应在 Product 组件中进行,如其他答案中所述。考虑到您需要进行 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.log(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]})
          });
          

          然后在您的Productrender() 函数中,您可以将 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.
          

          【讨论】:

            猜你喜欢
            • 2022-12-12
            • 2019-10-30
            • 1970-01-01
            • 2018-03-30
            • 1970-01-01
            • 2022-10-18
            • 2020-05-27
            • 2023-03-25
            • 2015-11-23
            相关资源
            最近更新 更多