【问题标题】:React fetch data in server before render在渲染之前反应在服务器中获取数据
【发布时间】:2015-06-19 03:59:01
【问题描述】:

我是 reactjs 新手,我想在服务器中获取数据,以便它将带有数据的页面发送到客户端。

当函数 getDefaultProps 返回类似 {data: {books: [{..}, {..}]}} 的虚拟数据时是可以的。

但不适用于以下代码。代码按此顺序执行,并显示错误消息“无法读取未定义的属性 'books'”

  1. getDefaultProps
  2. 返回
  3. 获取
  4. {数据:{书籍:[{..},{..}]}}

但是,我希望代码应该按这个顺序运行

  1. getDefaultProps
  2. 获取
  3. {数据:{书籍:[{..},{..}]}}
  4. 返回

有什么想法吗?

statics: {
    fetchData: function(callback) {
      var me = this;

      superagent.get('http://localhost:3100/api/books')
        .accept('json')
        .end(function(err, res){
          if (err) throw err;

          var data = {data: {books: res.body} }

          console.log('fetch');                  
          callback(data);  
        });
    }


getDefaultProps: function() {
    console.log('getDefaultProps');
    var me = this;
    me.data = '';

    this.fetchData(function(data){
        console.log('callback');
        console.log(data);
        me.data = data;      
      });

    console.log('return');
    return me.data;            
  },


  render: function() {
    console.log('render book-list');
    return (
      <div>
        <ul>
        {
          this.props.data.books.map(function(book) {
            return <li key={book.name}>{book.name}</li>
          })
        }
        </ul>
      </div>
    );
  }

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    你要找的是componentWillMount

    来自documentation

    在客户端和服务器上调用一次,紧接在 初始渲染发生。如果你在这个方法中调用setStaterender() 会看到更新后的状态,只会执行一次 尽管状态发生了变化。

    所以你会做这样的事情:

    componentWillMount : function () {
        var data = this.getData();
        this.setState({data : data});
    },
    

    这样,render() 只会被调用一次,并且您将在初始渲染中获得所需的数据。

    【讨论】:

    • ...但是如果 getData 触发异步请求?
    • @nav 对于异步请求,您必须设置一些初始状态,向用户指示正在获取数据(可能是加载图标)。您仍然可以在componentWillMount 中执行提取,并且在检索到数据时,您可以再次设置该状态以指示数据已完成加载,并将其显示给用户。
    • 是的,但是数据是在客户端而不是服务器上获取的。如果请求的内容正在服务器上呈现并且异步请求正在访问同一台服务器,那么 OP 不是要求保存此往返行程,在将响应发送到客户端之前处理这一切肯定更好吗?
    • @nav 你可以使用await this.getData()来同步触发这个请求
    • @MichaelParker componentWillMount 已弃用。您还有其他选择吗?
    【解决方案2】:

    一个非常简单的例子

    import React, { Component } from 'react';
    import { View, Text } from 'react-native';
    
    export default class App extends React.Component  {
    
        constructor(props) {
          super(props);
    
          this.state = {
            data : null
          };
        }
    
        componentWillMount() {
            this.renderMyData();
        }
    
        renderMyData(){
            fetch('https://your url')
                .then((response) => response.json())
                .then((responseJson) => {
                  this.setState({ data : responseJson })
                })
                .catch((error) => {
                  console.error(error);
                });
        }
    
        render(){
            return(
                <View>
                    {this.state.data ? <MyComponent data={this.state.data} /> : <MyLoadingComponnents /> }
                </View>
            );
        }
    }
    

    【讨论】:

      【解决方案3】:

      我用来从服务器接收数据并显示它的最佳答案

       constructor(props){
                  super(props);
                  this.state = {
                      items2 : [{}],
                      isLoading: true
                  }
      
              }
      
      componentWillMount (){
       axios({
                  method: 'get',
                  responseType: 'json',
                  url: '....',
      
              })
                  .then(response => {
                      self.setState({
                          items2: response ,
                          isLoading: false
                      });
                      console.log("Asmaa Almadhoun *** : " + self.state.items2);
                  })
                  .catch(error => {
                      console.log("Error *** : " + error);
                  });
          })}
      
      
      
          render() {
             return(
             { this.state.isLoading &&
                          <i className="fa fa-spinner fa-spin"></i>
      
                      }
                      { !this.state.isLoading &&
                  //external component passing Server data to its classes
                           <TestDynamic  items={this.state.items2}/> 
                      }
               ) }
      

      【讨论】:

        【解决方案4】:

        在 React 中,props 用于组件参数而不是用于处理数据。有一个单独的构造,称为state。每当您更新 state 时,组件基本上都会根据新值重新呈现自己。

        var BookList = React.createClass({
          // Fetches the book list from the server
          getBookList: function() {
            superagent.get('http://localhost:3100/api/books')
              .accept('json')
              .end(function(err, res) {
                if (err) throw err;
        
                this.setBookListState(res);
              });
          },
          // Custom function we'll use to update the component state
          setBookListState: function(books) {
            this.setState({
              books: books.data
            });
          },
          // React exposes this function to allow you to set the default state
          // of your component
          getInitialState: function() {
            return {
              books: []
            };
          },
          // React exposes this function, which you can think of as the
          // constructor of your component. Call for your data here.
          componentDidMount: function() {
            this.getBookList();
          },
          render: function() {
            var books = this.state.books.map(function(book) {
              return (
                <li key={book.key}>{book.name}</li>
              );
            });
        
            return (
              <div>
                <ul>
                  {books}
                </ul>
              </div>
            );
          }
        });
        

        【讨论】:

        • em...但据我所知,可以在渲染之前获取并准备好数据。您的示例将呈现两次。第一次渲染(使用空道具)> 获取数据和 setState > 再次渲染状态。如果我错了,请纠正我
        • 你是对的,组件会渲染两次。进行 ajax 调用是异步的,这是原始代码的问题。在调用 render 之前获取数据的唯一方法是,如果您有一个负责数据获取和装载 BookList 的父组件。即使在那时,您也必须更新该组件的状态,这将调用两次渲染。
        【解决方案5】:

        作为对Michael Parker回答的补充,可以让getData接受一个回调函数来激活setState更新数据:

        componentWillMount : function () {
            var data = this.getData(()=>this.setState({data : data}));
        },
        

        【讨论】:

          【解决方案6】:

          我也偶然发现了这个问题,学习了 React,并通过显示 spinner 来解决它,直到数据准备好。

              render() {
              if (this.state.data === null) {
                  return (
                      <div className="MyView">
                          <Spinner/>
                      </div>
                  );
              }
              else {
                  return(
                      <div className="MyView">
                          <ReactJson src={this.state.data}/>
                      </div>
                  );
              }
          }
          

          【讨论】:

          • 您可以检查状态是否为 falsy 而不是null,因此使用if (!this.state.data) { 会更干净
          【解决方案7】:

          如果有人仍在寻求答案,则用一个可能很简单的解决方案来回答类似的问题,问题是它涉及使用 redux-sagas:

          https://stackoverflow.com/a/38701184/978306

          或者直接跳到我写的关于这个主题的文章:

          https://medium.com/@navgarcha7891/react-server-side-rendering-with-simple-redux-store-hydration-9f77ab66900a

          【讨论】:

            【解决方案8】:

            您可以在尝试渲染之前使用redial 包在服务器上预取数据

            【讨论】:

              【解决方案9】:

              尝试使用componentDidMount

              componentDidMount : function () {
                  // Your code goes here
              },
              

              更多关于here

              如果您使用钩子,请使用useEffect 钩子:

              useEffect(() => { 
                  // Your code goes here
              });
              

              DocumentationuseEffect

              【讨论】:

                猜你喜欢
                • 2021-07-12
                • 2022-01-24
                • 1970-01-01
                • 2021-07-25
                • 2016-03-28
                • 1970-01-01
                • 1970-01-01
                • 2021-05-11
                • 2019-12-31
                相关资源
                最近更新 更多