I'm stuck with this and I cannot figure out what I'm doing wrong. I'm trying to do a Wikipedia Viewer (as explained here on Freecodecamp.com), basically a simple search of Wikipedia articles.
I've already done it in HTML/CSS/JS(jQuery) and now since I'm learning React I'm trying to recreate it in React.
I've split up my components, I'm using fetch to get data using Wikipedia API and everything is rendering, except the search results. I just cannot display the end result, which is the point of the whole "app".
Using React Dev Tools I already established that data is being fetched and props are being passed to child component and I've tested to see if a dummy child component would render and it did, so rendering all components isn't a problem, I'm just missing some step somewhere to get it to render that component with all the necessary data.
All code is in this code sandbox. I've set it up the way I have all set up locally so that you can clearly see how I'm doing things.
Any help is appreciated!
Sorry if the question is a little long, with all the text and code. I've also included all the code here split by files if that's more convenient for some people.
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;