Подтвердить что ты не робот

Реагировать на выборку данных на сервере перед рендерингом

Я новичок в реакции, я хочу получить данные на сервере, чтобы он отправил страницу с данными клиенту.

Это нормально, когда функция getDefaultProps возвращает фиктивные данные, подобные этому {data: {books: [{..}, {..}]}}.

Однако не работает с кодом ниже. Код выполняется в этой последовательности с сообщением об ошибке "Невозможно прочитать свойства" книги "undefined"

  • getDefaultProps
  • возвращение
  • извлечь
  • {data: {books: [{..}, {..}]}}

Однако, я ожидаю, что код должен работать в этой последовательности

  • getDefaultProps
  • извлечь
  • {data: {books: [{..}, {..}]}}
  • возвращение

Любая идея?

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

Ответ 1

То, что вы ищете, это componentWillMount.

Из документации:

Вызывается один раз, как на клиенте, так и на сервере, непосредственно перед происходит первоначальный рендеринг. Если вы вызываете setState в этом методе, render() будет видеть обновленное состояние и будет выполняться только один раз несмотря на изменение состояния.

Итак, вы сделали бы что-то вроде этого:

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

Таким образом, render() будет вызываться только один раз, и у вас будут данные, которые вы ищете в первоначальном рендере.

Ответ 2

В реакторе 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>
    );
  }
});

Ответ 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

В качестве дополнения к ответу Майкла Паркера вы можете заставить getData принять функцию обратного вызова для активации setState обновить данные:

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

Ответ 5

Очень простой пример этого

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

Ответ 6

Отвечая на аналогичный вопрос с потенциально простым решением этого, если кто-то все еще находится после ответа, уловка связана с использованием сокращений-саг:

fooobar.com/info/312721/...

Или просто перейдите прямо к статье, которую я написал по теме:

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