【问题标题】:Async data retrieval via input box is one step behind通过输入框检索异步数据落后了一步
【发布时间】:2016-03-26 22:56:22
【问题描述】:

我正在根据用户的输入制作一个简单的维基百科结果查看器。

只要输入框发生变化,结果列表就会更新。

我正在使用 $.getJSON() 来调用 Wikipedia API。但是,无论何时更改输入框,我的结果列表都不会更新。事实上,它似乎落后了一步,所以在更新状态方面肯定有一些我不理解的东西,特别是在异步调用中。

话虽如此,响应确实发生了变化,正如我在控制台中看到的那样,所以在结果列表的呈现中发生了一些我不理解的事情。

从 React 调试工具和控制台,我可以看到我的数组正在按预期更新,如下所示:

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Wiki Searcher</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
</head>
<body>
    <div id="container"></div>
    <script src="script.js"></script>
</body>
</html>

Javascript

var SearchBox = React.createClass({

    changeText: function () {
        this.props.changeInputText(ReactDOM.findDOMNode(this.refs.searchBox).value);
    },

    render: function () {
        return (
            <input type="text" onChange={this.changeText} ref="searchBox"/>
        )
    }
});

var SearchItemList = React.createClass({

    render: function () {

        console.log('data:', this.props.results);
        console.log('inputtext', this.props.inputText);

        var listItems = this.props.results
            .filter(function (e, i) {
                return e.title.indexOf(this.props.inputText) !== -1;
            }.bind(this))
            .map(function (e, i) {
            return (
                <li key={i}>
                    <a href="#"><h3>{e.title}</h3></a>
                    <p>{e.snippet}</p>
                </li>
            )
        });
        return (
            <ul>
                {listItems}
            </ul>
        )
    }
});
//TODO: extract list item into its own component?
var Main = React.createClass({

    getInitialState: function () {
        return {
            inputText: 'javascript',
            results: [],
        }
    },

    getWikiData: function () {

        var prependage = 'https://en.wikipedia.org/w/api.php?action=query&list=search&format=json&srsearch='
        var appendage = "&callback=?";
        var url = prependage + this.state.inputText + appendage;

        $.getJSON(url, function (data) {
            this.setState(
                {results: data.query.search}
            );
        }.bind(this));
    },

    componentDidMount: function () {
        this.getWikiData();
    },

    changeInputText: function (searchTerm) {
        this.setState({
            inputText: searchTerm,
        });
        this.getWikiData();
    },

    render: function () {
        return (
            <div className="container">
                <div className="col-sm-8 col-sm-offset-2">
                    <h1>Wiki Searcher</h1>
                    <SearchBox inputText={this.state.inputText} changeInputText={this.changeInputText}/>
                    <SearchItemList results={this.state.results} inputText={this.state.inputText}/>
                </div>
            </div>
        )
    }
});

ReactDOM.render(<Main/>, document.getElementById('container'));

Plunkr

【问题讨论】:

  • 顺便说一句,工作人员和所有工作人员的好问题。

标签: javascript asynchronous reactjs state


【解决方案1】:

主要错误在于您假设在您的changeInputText 函数中调用setState 会在您调用getWikiData 之前更改inputText

setState 是一个异步函数,因此当您的getWikiData 触发时,inputText 的新值可能不会被设置。

所以要修复,请在回调中调用getWikiData,当新状态更新时将触发。

changeInputText: function (searchTerm) {
    this.setState({
        inputText: searchTerm,
    }, () => {
       this.getWikiData();
    });  
},

【讨论】:

  • 谢谢你,它帮助我更多地了解setState()。但是,我仍然无法填充我的列表。它似乎不再“落后一步”,但它确实选择了何时填充列表。例如,查询ton 生成了一个列表,但tony 没有出现任何内容。有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-02
  • 2017-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多