List all items from array - javascript

I'm a beginner in react/web development and tried my first project. For the beginning I only want to list all pokemons from JS object in <li>.
I can't figure out what's wrong.
there's no error.
This is my code:
import React from "react";
import "./App.css";
var Pokedex = require("pokedex-promise-v2");
var P = new Pokedex();
class PokemonsList extends React.Component {
constructor(props) {
super(props);
this.state = { pokemonList: [] };
this.retrievePokemonList = this.retrievePokemonList.bind(this);
}
retrievePokemonList() {
P.getPokemonsList()
.then(function (response) {
const listItems = response.results.map((d) => <li key={d.name}>{d.name}</li>);
this.setState({
pokemonList: listItems
})
})
.catch(function(error) {
console.log(error);
});
}
render() {
//const listItems = response.results.map((d) => <li key={d.name}>{d.name}</li>);
return (
<div onLoad={this.retrievePokemonList}>
<h1>test</h1>
<div>{this.state.pokemonList}</div>
</div>
);
}
}
function App() {
return (
<div className="App">
<header className="App-header">
<PokemonsList></PokemonsList>
</header>
</div>
);
}
export default App;
In web console (F12) is this: Unchecked runtime.lastError: The message port closed before a response was received.
Where's my error? How can I display all those pokemons. Thanks in advance

Here is the your code corrected:
import React from 'react';
import PokedexLib from 'pokedex-promise-v2';
class PokemonsList extends React.Component {
constructor(props) {
super(props);
this.state = { pokemonList: [] };
this.Pokedex = new PokedexLib();
}
componentDidMount() {
this.Pokedex.getPokemonsList()
.then(response => {
this.setState({
pokemonList: response.results,
});
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
<div>
<h1>Pokemon List</h1>
<div>
{this.state.pokemonList.map(pokemon => (
<li key={pokemon.name}>{pokemon.name}</li>
))}
</div>
</div>
);
}
}
function App() {
return (
<div className='App'>
<header className='App-header'>
<PokemonsList></PokemonsList>
</header>
</div>
);
}
export default App;
Please look 2 things, all the apis call is better you will do in the componentDidMount method, and the other thing is you can render the list inside the method render with the map method.. regards

Related

render components from array by changing state

New to and learning React. I have a data file that I am reading in in order to render the Card component for each item. Right now, just one card with nothing in it (one card in the initial state) renders. How do I render multiple components by passing through properties from a data file?
Card.js
import React from 'react';
import * as d3 from "d3";
import data from './../data/data.csv';
class Card extends React.Component {
constructor(){
super();
this.state={
text:[],
}
}
componentDidMount() {
d3.csv(data)
.then(function(data){
console.log(data)
let text = data.forEach((item)=>{
console.log(item)
return(
<div key={item.key}>
<h1>{item.quote}</h1>
</div>
)
})
this.setState({text:text});
console.log(this.state.text);
})
.catch(function(error){
})
}
render() {
return(
<div className='card'>
{this.state.text}
</div>
)
}
}
export default Card
index.js
import Card from './components/Card'
ReactDOM.render(<Card />, document.getElementById('root'));
Answer:
(Found a good explanation here: https://icevanila.com/question/cannot-update-state-in-react-after-using-d3csv-to-load-data)
class Card extends React.Component {
state = {
data: []
};
componentDidMount() {
const self = this;
d3.csv(data).then(function(data) {
self.setState({ data: data });
});
function callback(data) {
this.setState({ data: data });
}
d3.csv(data).then(callback.bind(this));
}
render() {
return (
<div>
{this.state.data.map(item => (
<div className="card" key={item.key}>
<h1>{item.quote}</h1>
</div>
))}
</div>
);
}
}
I'd suggest store the response into a state then render the items with a map, something like:
constructor(){
...
this.state = {
data:[],
}
}
componentDidMount() {
...
.then(data => {
this.setState({
data,
})
})
}
render() {
return (
<div>
{this.state.data.map(item) => (
<div className='card' key={item.key}>
<h1>{item.quote}</h1>
</div>
)}
</div>
)
}

Can't set state data

I am new to react programming. It might be silly mistake but, i can't access state data in my smart component.
Following is my code.
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
resData: [],
}
}
componentDidMount() {
fetch(`http://someurl.com/something`)
.then(response => response.json())
.then(result => { alert(result.data[0].title); this.setState({ resData: result.data }));
}
render() {
return (
<div>
<Header />
<ErrorBoundary>
<Content data={ this.state.resData } />
</ErrorBoundary>
<Footer />
</div>
);
}
export default App;
If i alert data in following then it was there.
.then(result => { alert(result.data[0].title) setState({ resData: result.data })); //Here i can see my data.
I want to pass this state data to my component. But, there are no data.
<Content data={ this.state.resData } />
Any help would be greatly appreciated.
Try now:
You need to use this keyword with setState()
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
resData: [],
}
}
componentDidMount() {
fetch(`http://someurl.com/something`)
.then(function (response) {
return response.json()
})
.then(function (result) {
this.setState({ resData: result.data })
})
.catch(function (error) {
alert("Username password do not match")
})
}
render() {
const { resData } = this.state;
return (
<div>
{resData &&
<Header />
<ErrorBoundary>
<Content data={resData} />
</ErrorBoundary>
<Footer />
}
</div>
);
}
export default App;
Check it now
The alert is running before the setState is finishing, try running the alert as a callback to setState:
componentDidMount() {
fetch(`http://someurl.com/something`)
.then(response => response.json())
.then(result => this.setState({ resData: result.data }), () => {
alert(this.state.resData);
});
}
try this it might help
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
resData: [],
}
}
componentDidMount() {
var that = this;
fetch(`http://someurl.com/something`)
.then(response => response.json())
.then(result => { alert(result.data[0].title); that.setState({ resData: result.data }));
alert(that.state.resData);
}
render() {
var that = this;
return (
<div>
<Header />
<ErrorBoundary>
<Content data={ that.state.resData } />
</ErrorBoundary>
<Footer />
</div>
);
}
export default App;

React - onChange function 'this.state' is undefined

I'm experimenting with React and I'm trying to create a Search to filter a list of items. I have two components, the main one displaying the list of items which calls the Search component.
I have an onChange function that sets the term in the state as the input value and then calls searchItems from the main component to filter the list of items. For some reason in searchItems, this.state is undefined. I thought adding bind to onInputChange in the Search component would sort it out but it did not make any difference. Maybe there's something I'm missing.
Main Component
import React, { Component } from 'react';
import _ from 'lodash';
import Search from './search';
class Items extends Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
items: []
};
}
componentDidMount() {
fetch("[url].json")
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result
});
}
),
(error) => {
this.setState({
isLoaded: true,
error
})
}
}
searchItems(term) {
const { items } = this.state;
const filtered = _.filter(items, function(item) {
return item.Name.indexOf(term) > -1;
});
this.setState({ items: filtered });
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
}
else if (!isLoaded) {
return <div>Loading...</div>;
}
else {
return (
<div>
<Search onSearch={this.searchItems}/>
<ul>
{items.map(item => (
<li key={item.GameId}>
{item.Name}
</li>
))}
</ul>
</div>
)
}
}
}
export default Items;
Search Component
import React, { Component } from 'react';
class Search extends Component {
constructor(props) {
super(props);
this.state = {
term: ''
};
}
render() {
return (
<div>
<input type="text" placeholder="Search" value={this.state.term} onChange={event => this.onInputChange(event.target.value)} />
</div>
);
}
onInputChange(term) {
this.setState({ term });
this.props.onSearch(term);
}
}
export default Search;
You didn't bind searchItems() in the Items component.
Try changing it to an arrow function:
searchItems = () => {
// blah
}
or otherwise binding it in the constructor():
constructor() {
// blah
this.searchItems = this.searchItems.bind(this);
}
or when you call it.
You can read more about this here.

How to apply load more button to push this.state in React

The purpose of implementing <a className="button" onClick={this.loadMore}>Load more news</a> button is to take more objects with API and show without refresh the page. Still not sure the way to implementing setState method is ideal or not
this.setState({
newsData: [...this.state.newsData, ...responseJson]
})
App.js
import React from 'react';
import { Newslist } from './newslist/Newslist';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
page: 1,
newsData: ''
}
}
componentDidMount() {
this.page = 1;
this.requestNews();
}
requestNews () {
console.log('koooy');
fetch('http://localhost:3000/api/?page='+this.page)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
newsData: [...this.state.newsData, ...responseJson]
})
})
.catch((error) => {
console.error(error);
});
}
loadMore = () => {
this.requestNews();
}
render() {
return (
<main className="main">
<h1>Hello mate !</h1>
<Paggination />
{ this.state.newsData.length
? <Newslist currentNews={this.state.newsData} loadMoreData={this.loadMore} />
: <p>Loading...</p>
}
</main>
);
}
}
export default App;
Newslist.js
import React from 'react';
export class Newslist extends React.Component {
loadMore = () => {
event.preventDefault();
this.props.loadMoreData();
}
render () {
const newsInList = this.props.currentNews.map(newsDetails => {
return (
<section className="media" key={newsDetails.id}>
{newsDetails.image && <figure className="media-figure">
<img src={newsDetails.image} />
</figure>}
<div className="media-body">
<h3 className="media-title">{newsDetails.header}</h3>
<p>{newsDetails.content}</p>
</div>
</section>
);
});
return (
<div>
{newsInList}
<a className="button" onClick={this.loadMore}>Load more news</a>
</div>
);
}
}
What you have done seems reasonable. Basically, make sure you know your current news page/offset. When you make the API request, send the page/offset with the request and append the new use to the head or tail of the array.
I noticed a suggestion about the usage of Redux, Redux is rather complicated and this is a very simple issue, no need for it here.

How to update a parent's component state from a child component in Reactjs

I am passing the state of the parent component from the parent component to the child component.And in the child component,I have a different state.I am performing some actions on the child component's state and the result of that has to be added to the parent component's state.So,in my parent component I have written a callback function which will update the state of the parent component.The code is:
updateState = (booksList) => {
this.setState({books : this.state.books.push(booksList)});
}
So,this function is then passed to the child component as props:
<BookSearch
books={this.state.books}
handleShelfChange={this.handleShelfChange}
updateState={this.updateState}/>
Then in my child component,I am trying to implement the callback function as :
let getBook = this.state.books.filter(filteredBook => filteredBook.shelf !== "none")
this.props.updateState(getBook)
But this is not working as expected.Is this the correct way?Can anyone please help me with this?
I have tried to solve my problem by implementing the solution provided here : How to pass data from child component to its parent in ReactJS? , but I am getting some errors.
EDIT
Parent component : App.js
import React from 'react'
import * as BooksAPI from './BooksAPI'
import { Link } from 'react-router-dom'
import { Route } from 'react-router-dom'
import './App.css'
import BookList from './BookList'
import BookSearch from './BookSearch'
class BooksApp extends React.Component {
constructor(props) {
super(props);
this.state = {
books: [],
showSearchPage : false
};
//this.updateState = this.updateState.bind(this)
}
componentDidMount() {
BooksAPI.getAll().then((books) => {
this.setState({ books })
})
console.log(this.state.books);
}
filterByShelf = (bookName,shelfName) =>
bookName.filter(book => book.shelf===shelfName)
isTheBookNew = book => {
let is = false;
if (book.shelf === "none")
{ this.setState(state =>
{
books: state.books.push(book)});
is = true;
console.log(this.state.books);
}
return is;
};
handleShelfChange = (bookOnChange, newSehlf) => {
!this.isTheBookNew(bookOnChange) && this.setState(state => {
let newBooks = state.books.map(book =>
{ if (bookOnChange.id === book.id)
{ book.shelf = newSehlf; }
return book;
});
return {
books: newBooks
};
}
);
BooksAPI.update(bookOnChange, newSehlf);
};
updateState = (booksList) => {
const books = [...this.state.books, booksList]
this.setState({ books });
}
render() {
return (
<div className="app">
<Route exact path="/" render={() => (
<div className="list-books">
<div className="list-books-title">
<h1>MyReads</h1>
</div>
<BookList
books={this.filterByShelf(this.state.books,'currentlyReading')}
shelfName='Currently Reading'
handleShelfChange={this.handleShelfChange}/>
<BookList
books={this.filterByShelf(this.state.books,'wantToRead')}
shelfName='Want to Read'
handleShelfChange={this.handleShelfChange}/>
<BookList
books={this.filterByShelf(this.state.books,'read')}
shelfName='Read'
handleShelfChange={this.handleShelfChange}/>
<div className="open-search">
<Link
to="./search" />
</div>
</div>
)
} />
<Route path="/search" render={() =>
<BookSearch
books={this.state.books}
handleShelfChange={this.handleShelfChange}
updateState={this.updateState}/>
} />
</div>
)
}
}
export default BooksApp
BookSearch.js :
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import escapeRegExp from 'escape-string-regexp'
import sortBy from 'sort-by'
import * as BooksAPI from './BooksAPI'
import BookList from './BookList'
class BookSearch extends Component {
constructor(props) {
super(props);
this.state = {
search:'',
books:[]
}
}
updateSearch = (searchString) => {
this.setState({search: searchString.trim()})
let searchResults = BooksAPI.search(this.state.search,1).then((book_search) => {
if (book_search != undefined) {
console.log(book_search);
book_search.map((book) => book.shelf = 'none');
this.setState({ books : book_search }, this.check); // callback function to this.setState
console.log(this.state.books)
}
})
}
check = () => {
let parent_books = this.props.books;
console.log(this.state.books)
const book_result = this.state.books.map((book) => {
const parent = parent_books.find(parent => parent.title === book.title );
if(parent) {
//console.log(parent);
book.shelf = parent.shelf;
//console.log(book)
}
return book;
})
this.setState({books: book_result}, () => {console.log(this.state.books)})
}
updateParentState = () => {
let getBook = this.state.books.filter(filteredBook => filteredBook.shelf !== "none")
this.props.updateState(getBook)
}
render() {
return(
<div className="search-books">
<div className="search-books-bar">
<Link
to="/"
className="close-search">
Close
</Link>
<div className="search-books-input-wrapper">
<input
type="text"
placeholder="Search by title or author"
value={this.state.search}
onChange={(event) => this.updateSearch(event.target.value)}/>
</div>
</div>
<div className="search-books-results">
<ol className="books-grid">
<BookList
books={this.state.books}
handleShelfChange={this.props.handleShelfChange}
updateParentState={this.updateParentState}/>
</ol>
</div>
</div>
)
}
}
export default BookSearch
BookList.js
import React, { Component } from 'react';
import Book from './Book'
class BookList extends Component {
constructor(props) {
super(props);
this.state = {
showSearchPage : false
}
console.log(this.props.books)
}
render() {
return(
<div className="app">
<div>
<div className="list-books-content">
<div>
<div className="bookshelf">
<h2 className="bookshelf-title">{this.props.shelfName}</h2>
<div className="bookshelf-books">
<ol className="books-grid">
{this.props.books.map(book =>
<li key={book.title}>
<Book
book={book}
handleShelfChange={this.props.handleShelfChange}
update={this.props.updateParentState} />
</li>)
}
</ol>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default BookList;
Book.js
import React, { Component } from 'react'
class Book extends Component {
constructor(props) {
super(props);
this.props.updateParentState;
}
render() {
return(
<div className="book">
<div key={this.props.book.title}>
<div className="book-top">
<div className="book-cover" style={{width:128, height:193, backgroundImage: `url(${this.props.book.imageLinks.thumbnail})`}}>
<div className="book-shelf-changer">
<select id="bookName" value={this.props.book.shelf}
onChange={(event) => this.props.handleShelfChange(this.props.book, event.target.value)}>
<option value="moveTo" disabled>Move to...</option>
<option value="currentlyReading">Currently Reading</option>
<option value="wantToRead">Want to Read</option>
<option value="read">Read</option>
<option value="none">None</option>
</select>
</div>
</div>
</div>
<div className="book-title">{this.props.book.title}</div>
<div className="book-authors">{this.props.book.authors}</div>
</div>
</div>
)
}
}
export default Book
So, I have 4 components as shown above.From App component,I am calling BookSearch component where I can search for books and send the books to App component by selecting the value in dropdown. Each book in BookSearch component will initially be assigned a shelf property of "none".When a user selects a shelf value from Booksearch,the book will automatically be added to the App component.So,when I navigate back to the App component from BookSearch,I should be able to see the book in the assigned shelf.So,for this case,I am using the updateSearch function. The books are displayed through the Book component which has the dropdown value.
If i understood this correctly, you are mutating the state in the function updateState.
What you should be doing instead is,
const updateState = (booksList) => {
const books = [ ...this.state.books, ...booklist ];
this.setState({ books });
}
In parent component constructor add the following line:
this.updateState = this.updateState.bind(this)
More at https://reactjs.org/docs/handling-events.html

Categories