在渲染之前在服务器中react获取数据

IT技术 reactjs
2021-04-10 08:52:39

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

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

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

  1. 获取默认props
  2. 返回
  3. 拿来
  4. {数据:{书籍:[{..},{..}]}}

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

  1. 获取默认props
  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>
    );
  }
6个回答

你要找的是componentWillMount.

文档

在客户端和服务器上调用一次,紧接在初始呈现发生之前。如果您setState在此方法中调用render()将看到更新的状态,并且尽管状态发生变化也只会执行一次。

所以你会做这样的事情:

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

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

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

一个非常简单的例子

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

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

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

在 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 > 再次渲染状态。如我错了请纠正我
2021-05-31 08:52:39
你是对的,组件会渲染两次。进行 ajax 调用是异步的,这是原始代码的问题。在调用 render 之前获取数据的唯一方法是,如果您有一个负责数据获取和安装的父组件BookList即使在那时,您也必须更新该组件的状态,该组件将调用两次渲染。
2021-05-31 08:52:39

作为迈克尔帕克答案的补充,您可以让 getData 接受一个回调函数来激活 setState 更新数据:

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