即使正确传递子组件道具也无法呈现它们

时间:2017-05-30 17:23:10

标签: javascript reactjs

我坚持这一点,我无法弄清楚我做错了什么。我试图做一个维基百科查看器(如Freecodecamp.com所述),基本上是对维基百科文章的简单搜索。

我已经在HTML / CSS / JS(jQuery)中完成了它,现在因为我正在学习React,我试图在React中重新创建它。

我已经拆分了我的组件,我使用fetch来使用Wikipedia API获取数据,除搜索结果外,所有内容都在渲染。我只是无法显示最终结果,这是整个" app"。

的重点。

使用React Dev Tools我已经确定正在获取数据并且道具正被传递给子组件并且我已经过测试以查看虚拟子组件是否会呈现并且它已经完成,因此渲染所有组件并非如此。 ;问题,我在某个地方错过了一些步骤,让它用所有必要的数据渲染该组件。

所有代码都在this代码沙箱中。我已经按照我在本地设置的方式进行设置,以便您可以清楚地了解我是如何做事的。

感谢任何帮助!

很抱歉,如果问题有点长,包含所有文字和代码。我还包括了按文件分割的所有代码,如果这对某些人来说更方便。

App.jsx

import React from 'react';
import WikiHeader from './Header';
import WikiSearch from './Search';
import OutputList from './OutputList';
import 'purecss';
import 'purecss/build/grids-responsive-min.css'
import './App.css';

var resultsArray = [];
const wikiAPI = "https://en.wikipedia.org/w/api.php?&";
var wikiHeaders = {
  action: "query",
  format: "json",
  origin: "*",
  prop: "info|extracts",
  exsentences: 2,
  exlimit: 5,
  generator: "search",
  inprop: "url",
  gsrsearch: "",
  gsrnamespace: 0,
  gsrlimit: 5,
  exintro: 1
};

// Format headers to be used for a query string
function toQueryString(obj) {
  var parts = [];
  for (var i in obj) {
    if (obj.hasOwnProperty(i)) {
      parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
    }
  }
  return parts.join("&");
}

class App extends React.Component {

  constructor() {
    super();

    this.state = {
      results: []
    }

    this.ajaxCall = this.ajaxCall.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  // AJAX using fetch
  ajaxCall() {
    resultsArray = []; // clear array every time ajax is called so that it doesn't just add new items to previous items
    toQueryString(wikiHeaders);

    fetch(wikiAPI + toQueryString(wikiHeaders)).then(function(response) {
      return response.json();
    }).then(function(json) {
      for (var prop in json.query.pages) {

        // push response items to array so that state isn't directly changed (not changing state recommended by Facebook)
        resultsArray.push({
          title: json.query.pages[prop].title,
          url: json.query.pages[prop].fullurl,
          extract: json.query.pages[prop].extract
        });
      }
    }).catch(function(ex) {
      console.log('Json parsing failed', ex); // show error if JSON parsing fails
    });

    this.setState({results: resultsArray}); // set state.results to resultsArray
  }

  handleChange(e) {
    wikiHeaders.gsrsearch = e.target.value; // get input value and store it
  }

  handleSubmit(e) {
    e.preventDefault();
    console.log("Hey, this is a submit event!"); // show if function is being called

    // Call fetch
    this.ajaxCall();

    // Clear the search box after submit
    document.getElementById("search-input").value = "";
  }


  render() {
    return (
      <div className="full-wrapper pure-g">
        <div className="pure-u-1">
          <WikiHeader />
          <WikiSearch onChange={this.handleChange} onSubmit={this.handleSubmit} />
          <OutputList results={this.state.results} />
        </div>
      </div>
    );
  }
}

export default App;

Header.jsx

import React from 'react';

class WikiHeader extends React.Component {
  render() {
    return (
      <h1 className="site-title">Wikipedia Viewer</h1>
    );
  }
};

export default WikiHeader;

Search.jsx

import React from 'react';

class WikiSearch extends React.Component {

  render() {
    return (
      <div className="search-input">
        <form className="pure-form" onSubmit={this.props.onSubmit}>
          <div className="pure-u-1 pure-u-md-3-4">
            <input type="text" id="search-input" onChange={this.props.onChange} className="pure-input pure-u-1" placeholder="Input your search term here..."></input>
          </div>
          <div className="pure-u-1 pure-u-md-1-4 button-wrapper">
            <button type="submit" id="search-button" className="pure-button pure-button-primary pure-u-1 pure-u-md-23-24">Search</button>
          </div>
        </form>
        <a href="https://en.wikipedia.org/wiki/Special:Random" alt="Open a Random Wikipedia article" target="_blank" rel="noopener noreferrer">or see a random Wikipedia article</a>
      </div>
    );
  }

};

export default WikiSearch;

OutputList.jsx

import React from 'react';
import OutputItem from './OutputItem';

class OutputList extends React.Component {
  render() {

    var finalResult = this.props.results.map((result, index) => {
      return (
        <OutputItem
          key={index}
          title={result.title}
          url={result.url}
          extract={result.extract}
        />
      );
    });

    return (
      <div id="search-output" className="pure-g">
        <ul className="article-list pure-u-1">
          {finalResult}
        </ul>
      </div>
    );
  }
}

export default OutputList;

OutputItem.jsx

import React from 'react';

class OutputItem extends React.Component {
  render() {
    return (
      <div>
        <li className="pure-u-1">
          <a href={this.props.url} target="_blank" rel="noopener noreferrer">
            <h2>{this.props.title}</h2>
            {this.props.extract}
          </a>
        </li>
      </div>
    );
  }
}

export default OutputItem;

2 个答案:

答案 0 :(得分:0)

我想我设法让它在你的沙盒上工作。

this.setState({results: resultsArray});在错误的时间完成。它必须等待AJAX​​调用完成。我把它放在你身后 for (var prop in json.query.pages) {循环,因此在ajax解析回调中。

由此产生的问题是this不再引用组件实例,因此this.setState变为未定义。为了避免这个问题,我将).then(function(json) {转换为箭头函数,以便它不会覆盖this

Here您可以看到我更新的沙盒。

答案 1 :(得分:0)

如果我将some logging添加到您当前的应用并运行它,我可以观察到您的finalResults变量为空,即使查询有效。这是因为resultsArray中的fetch变量与Javascript上下文之外的var that = this;变量不同。

您可以先在setState中提升旧的上下文,然后在需要执行另一个filter1 = null; filter2 = "foo"时完全使用它。

https://codesandbox.io/s/KZvXP7kKn