render components from array by changing state - javascript

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>
)
}

Related

React props and Component

I have a problem I can not solve myself in relation to react.
What I am trying to do is add props to my Component
So I can use my compnent again and again just with a string relative to a variable so I can just write e.g.
I really searched for some different things but none that worked.
Just hoping you can get me on.
Hope it makes sense otherwise feel free to ask
My Component
import React, { Component } from "react";
export default class UserSelections extends Component {
constructor(props) {
super(props);
this.state = {
items: [],
DataisLoaded: false,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('Your favorite flavor is: ' + this.state.value);
event.preventDefault();
}
// ComponentDidMount is used to
// execute the code
componentDidMount() {
fetch(
"URL")
.then((res) => res.json())
.then((json) => {
this.setState({
items: json,
DataisLoaded: true
});
})
}
render() {
const { DataisLoaded, items } = this.state;
if (!DataisLoaded) return <div>
<h1> Vent et øjeblik... </h1> </div> ;
return (
<div className = "App">
<h1> Fetch data from an api in react </h1>
<form onSubmit={this.handleSubmit}>
<label><select name={this.state.slug} value={this.state.value} onChange={this.handleChange}>
{ --->Need Variable here<--- Down here
items.filter(slug => slug.slug === **'bygnings-st'**).map((item, index) => (
<option value={ item.outputvalue } key={index}>{ item.outputvalue }</option>
))
}</select>
</label>
<input type="submit" value="Submit" />
</form>
</div>
);
}
}
import React from "react";
import UserSelections from "./components/UserSelections";
import './App.css';
function App() {
return (
<div className="App">
<UserSelections **Need props here** /> <-------------------
</div>
);
}
export default App;
Best regards
Morten
If you want to pass a string as prop:
const value = "hi";
<UserSelections stringProp={value} />
And you display the value with:
{this.props.stringProp}
inside of the UserSelections component

List all items from array

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

React state not setting

it seems as if this set of code is not updating my state, and I am not sure why! The api is 100% sending back TRUE (as seen from axios console.log). Thank you advanced for the help!
import React, { Component } from 'react';
import axios from 'axios';
export class Test extends Component {
state = {
reponse: false
}
componentDidMount () {
axios.get(`/api`)
.then(res => {
console.log(res.data.success);
this.setState({ response: res.data.success });
});
}
render() {
if (this.state.reponse) {
return (
<div>
<h1>Response Gathered!</h1>
</div>
)
} else {
return (
<div>
<button onClick={() => console.log(this.state.reponse)}>Check State</button>
</div>
)
}
}
}
export default Test;
Change,
state = {
reponse: false
}
To,
state = {
response: false
}
There is a typo in state declaration (reponse to response)..
And modified code would look like,
class Test extends React.Component {
state = {
response: false
};
componentDidMount() {
axios.get(`/api`)
.then(res => {
console.log(res.data.success);
this.setState({ response: res.data.success });
});
}
render() {
if (this.state.response) {
return (
<div>
<h1>Response Gathered!</h1>
</div>
);
} else {
return (
<div>
<button onClick={() => console.log(this.state.response)}>
Check State
</button>
</div>
);
}
}
}
export default Test;
Working Codesandbox example
define state in the constructor function.
constructor(props) {
super(props);
this.state = {response: false};
}
btw, there was a spelling error.
render() {
return (
{this.state.response ?
<h1>Some text</h1> :
(<div>
<button onClick={() => console.log(this.state.response)}>
Check State
</button>
</div>)
}
);
}

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.

Categories