【问题标题】:React failed to set state in the function invoked inside componentWillMount()React 未能在 componentWillMount() 内部调用的函数中设置状态
【发布时间】:2017-05-11 07:34:28
【问题描述】:

我是新来的反应。我正在尝试使用_fetchUsers() 动态地从远程服务器获取数据。单击不同的导航选项卡时应更改状态 apiUrl,尽管此处未显示。问题,我发现$.ajax函数之前的日志显示this.state.apiurl的空字符串。如果我在 ajax 的 url 属性上对 url 进行硬编码,则 ajax 可以返回正确的响应。有人可以解释为什么我无法为 apiurl 设置状态,是与 componentWillMount() 相关的原因

export default class RegiteredUserTable extends Component {
    constructor() {
        super();
        this.state = {
            registeredUsers:[],
            tableProperties:[],
            apiUrl:''
        }
    }
    _fetchUsers() {
        console.log("this.props", this.props);
        if(this.props.match.params.tableId === "buyer-table"){
            this.setState({apiUrl:'/buyers/list-buyers'});
        } else if (this.props.match.params.tableId === "seller-table") {
            this.setState({apiUrl:'/sellers/list-sellers/'});
        }
        console.log('this.state.apiUrl',this.state.apiUrl);    
        $.ajax({
            method: 'GET',
            url: `${this.state.apiUrl}`,
            success: (res) => {
                console.log('res',res);
                let registeredUsers = res.data;
                this.setState({registeredUsers});
            }
        });
    }

    _getTableProperty() {
        //property array
        console.log('this.state.registeredUsers',this.state.registeredUsers);
        const tableProperties = this.state.registeredUsers[0].keys;
        this.setState({tableProperties});
        return tableProperties.map(tableProperty => {
            return  (
                        <th>{tableProperty}</th>
                    )
        })
    }

    _getUsers() {
        return this.state.registeredUsers.map(registeredUser => {
                return (
                    <tr>
                        <td>{registeredUser.id}</td>
                        <td>{registeredUser.first_name}</td>
                        <td>{registeredUser.last_name}</td>
                    </tr>
                );
            }
        )
    }
    componentWillMount() {
        this._fetchUsers();
    }
    render() {
        return(
            <div className="container">
                <div className="row">
                    <div className="col-xs-12">
                    <div className="table-responsive">
                        <table className="table table-bordered table-hover">
                        <caption className="text-center">Agents' data</caption>
                        <thead>
                            <tr>
                                {this._getTableProperty()}
                            </tr>
                        </thead>
                        <tbody>
                            {this._getUsers()}
                        </tbody>
                        <tfoot>
                            <tr>
                            <td colSpan="5" className="text-center">Data retrieved from <a href="http://www.infoplease.com/ipa/A0855611.html" target="_blank">infoplease</a> and <a href="http://www.worldometers.info/world-population/population-by-country/" target="_blank">worldometers</a>.</td>
                            </tr>
                        </tfoot>
                        </table>
                    </div>
                    </div>
                </div>
            </div>

        );
    }
}

【问题讨论】:

标签: reactjs


【解决方案1】:

SetState 是异步的,所以一旦setState 将apiUrl 设置在state 变量中,使用回调方法并在其中进行api 调用。

像这样写_fetchUsers

_fetchUsers() {
    let tableId = this.props.match.params.tableId;

    this.setState({
        apiUrl: tableId === "buyer-table" ? '/buyers/list-buyers' : '/sellers/list-sellers/'
    }, () => {
         $.ajax({
            method: 'GET',
            url: `${this.state.apiUrl}`,
            success: (res) => {
                console.log('res',res);
                let registeredUsers = res.data;
                this.setState({registeredUsers});
            }
        });
    });       
}

或者更好的方法是将apiUrl 存储在一个变量中,并在收到响应后执行setState,这样您就不需要两次执行setState,也不需要依赖第一个setState

像这样:

_fetchUsers() {
    let tableId = this.props.match.params.tableId;
    let url = tableId === "buyer-table" ? '/buyers/list-buyers' : '/sellers/list-sellers/';
    $.ajax({
        method: 'GET',
        url: url,
        success: (res) => {
            console.log('res',res);
            let registeredUsers = res.data;
            this.setState({registeredUsers, apiUrl: url});
        }
    });       
}

【讨论】:

  • 如果值不会改变,你应该使用const,而不是let
  • 您好,我使用了您的方法,并且确实获得了日志中显示的 apiUrl 状态的正确数据。然而,我发现了另一个问题。函数 _getTableProperty() 中注册用户状态的日志仍然是空的。我以为我已经调用了 _fetchUsers() 来设置函数 componentWillMount() 中的注册用户状态,以使其在渲染之前准备好,但实际上,根据我的日志信息,它的行为不像我想的那样。这是为什么呢?
  • 我找到了答案,在这种情况下 _getTableProperty() 被调用了两次。第一次为空(初始),第二次在componentWillMount()完成后调用,获取数据。如果我想更新 url 取决于不同的 url 参数,我应该再次调用 componentWillReceiveProps() 方法中的 _fetchUsers,参考stackoverflow.com/questions/38915066/…
猜你喜欢
  • 1970-01-01
  • 2017-03-05
  • 1970-01-01
  • 2020-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-13
  • 1970-01-01
相关资源
最近更新 更多