Reactjs hiển thị không đồng bộ của các thành phần


82

Tôi muốn hiển thị thành phần của mình sau khi yêu cầu ajax của tôi được thực hiện.

Dưới đây bạn có thể thấy mã của tôi

var CategoriesSetup = React.createClass({

    render: function(){
        var rows = [];
        $.get('http://foobar.io/api/v1/listings/categories/').done(function (data) {
            $.each(data, function(index, element){
                rows.push(<OptionRow obj={element} />);
            });
           return (<Input type='select'>{rows}</Input>)

        })

    }
});

Nhưng tôi gặp lỗi bên dưới vì tôi đang trả về kết xuất bên trong phương thức done của yêu cầu ajax của tôi.

Uncaught Error: Invariant Violation: CategoriesSetup.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.

Có cách nào để đợi yêu cầu ajax của tôi kết thúc trước khi bắt đầu hiển thị không?


3
Ngoài ra, một nitpick nhỏ nhưng có khả năng truy xuất dữ liệu trong quy trình kết xuất () không thực sự là một ý tưởng tuyệt vời. Giữ render () để hiển thị và trừu tượng hóa phần còn lại. Ngoài ra, bạn có thể chỉ muốn lấy dữ liệu đó một lần, không phải mọi khi thành phần được hiển thị.
Phil Cooper

Câu trả lời:


131

Có hai cách để xử lý điều này và bạn chọn cách nào tùy thuộc vào thành phần nào sẽ sở hữu dữ liệu và trạng thái tải.

  1. Di chuyển yêu cầu Ajax vào cha mẹ và hiển thị thành phần có điều kiện:

    var Parent = React.createClass({
      getInitialState: function() {
        return { data: null };
      },
    
      componentDidMount: function() {
        $.get('http://foobar.io/api/v1/listings/categories/').done(function(data) {
          this.setState({data: data});
        }.bind(this));
      },
    
      render: function() {
        if (this.state.data) {
          return <CategoriesSetup data={this.state.data} />;
        }
    
        return <div>Loading...</div>;
      }
    });
    
  2. Giữ yêu cầu Ajax trong thành phần và hiển thị thứ gì đó khác có điều kiện khi nó đang tải:

    var CategoriesSetup = React.createClass({
      getInitialState: function() {
        return { data: null };
      },
    
      componentDidMount: function() {
        $.get('http://foobar.io/api/v1/listings/categories/').done(function(data) {
          this.setState({data: data});
        }.bind(this));
      },
    
      render: function() {
        if (this.state.data) {
          return <Input type="select">{this.state.data.map(this.renderRow)}</Input>;
        }
    
        return <div>Loading...</div>;
      },
    
      renderRow: function(row) {
        return <OptionRow obj={row} />;
      }
    });
    

6
Tôi đã tình cờ tìm thấy câu trả lời này vào năm 2017, liệu hai giải pháp tốt nhất này có còn tốt nhất để sử dụng không?
Dan

@Dan React kết xuất giao diện người dùng dựa trên đạo cụ và trạng thái, vì vậy khái niệm cốt lõi sẽ vẫn giữ nguyên - thực hiện yêu cầu Ajax, đặt một số trạng thái và kết xuất lại thứ gì đó. Tuy nhiên, các mẫu như các thành phần bậc cao đã trở nên phổ biến hơn, chứng tỏ cách người ta có thể loại bỏ sự phức tạp.
Michelle Tilley

1
if (this.state.data)nên là if (this.state && this.state.data)vì đôi khi trạng thái có thể là null.
Timo

@Timo Hm, trong trường hợp nào sẽ this.statenull?
Michelle Tilley

6
@Timo khởi tạo trạng thái trong hàm tạo
Louis

8

Dưới đây là ví dụ cơ bản về kết xuất không đồng bộ của các thành phần:

import React                from 'react';
import ReactDOM             from 'react-dom';        
import PropTypes            from 'prop-types';

export default class YourComponent extends React.PureComponent {
    constructor(props){
        super(props);
        this.state = {
            data: null
        }       
    }

    componentDidMount(){
        const data = {
                optPost: 'userToStat01',
                message: 'We make a research of fetch'
            };
        const endpoint = 'http://example.com/api/phpGetPost.php';       
        const setState = this.setState.bind(this);      
        fetch(endpoint, {
            method: 'POST',
            body: JSON.stringify(data)
        })
        .then((resp) => resp.json())
        .then(function(response) {
            setState({data: response.message});
        });
    }

    render(){
        return (<div>
            {this.state.data === null ? 
                <div>Loading</div>
            :
                <div>{this.state.data}</div>
            }
        </div>);
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.