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;
Related
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>
)
}
I'm trying to initiate an API request upon paste of a URL into an input field and then show the result on the page.
According to documentation and this link on SOF, setState is the way to initiate re-render, I know and it seems I did it the right way myself, but something is off, I get the url state only when I do onChange again, React doesn't seem to show me my pasted data anywhere in any of the available lifecycle events.
Using create-react-app:
import React from "react";
import ReactDOM from "react-dom";
const UserInput = props => {
return (
<div>
<label>Enter URL:</label>
<input onChange={props.handleChange} type="text" value={props.value} />
</div>
);
};
class Fetch extends React.Component {
constructor() {
super();
this.state = {
url: null,
userData: null,
fetching: false,
error: null
};
}
componentDidUpdate() {
this.fetchData();
}
fetchData() {
fetch(this.state.url)
.then(result => result.json())
.then(json => this.setState({ userData: json }))
.error(error => console.log(error));
}
render() {
return this.props.render();
}
}
const UserProfile = ({ name, gender }) => {
return (
<div>
Hey {name}, you are {gender}!
</div>
);
};
class App extends React.Component {
constructor() {
super();
this.state = {
url: null
};
}
handleChange(e) {
this.setState({
url: e.target.value
});
}
render() {
return (
<div>
<UserInput
value={this.state.url}
handleChange={this.handleChange.bind(this)}
/>
<Fetch url={this.state.url} render={data => <UserProfile />} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
If you paste any URL in the field, you won't have it in state, so when fetchData is triggered its
this.state.url
is actually still null.
Thanks
Your Fetch component and App component are using two separate copies of the url state which causes the issue, you have to use the url you pass as prop to the Fetch component instead.
class Fetch extends React.Component {
constructor(props) {
super(props);
this.state = {
// url: null, remove this
userData: null,
fetching: false,
error: null
};
}
componentDidUpdate() {
this.fetchData();
}
fetchData() {
fetch(this.props.url) // update here
.then(result => result.json())
.then(json => this.setState({ userData: json }))
.error(error => console.log(error));
}
render() {
return this.props.render(userData); // the render prop is a function in your case that expects data
}
}
update the below line too so that the UserProfile gets the data that has been obtained from API. I am not sure about the keys
<Fetch url={this.state.url} render={data => <UserProfile name={data.name} gender={data.gender}/>} />
Trying to fetch the Jsonplaceholder users name and id and filter them in in the render method. I'm getting this error:
TypeError: this.state.robots.filter is not a function
class App extends React.Component {
constructor() {
super()
this.state = {
robots: [],
searchfield: ''
}
}
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => {
return response.json;
})
.then((users) => {
this.setState({robots: users});
})
}
onSearchChange = (event) => {
this.setState({searchfield: event.target.value});
}
render() {
const filteredRobots = this.state.robots.filter(robot => {
return robot.name.toLowerCase().includes(this.state.searchfield.toLowerCase());
})
return (
<div className="container text-center mt-4">
<h1 className="custom mb-5">RoboFriends</h1>
<SearchBox searchChange={this.onSearchChange} />
<CardList robots={filteredRobots} />
</div>
);
}
}
Could anyone give me a clue how to solve the problem? Thank you in advance!
You have to use .json() not json.
class App extends React.Component {
constructor() {
super()
this.state = {
robots: [],
searchfield: ''
}
}
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => {
return response.json();
})
.then((users) => {
this.setState({robots: users});
})
}
onSearchChange = (event) => {
this.setState({searchfield: event.target.value});
}
render() {
const filteredRobots = this.state.robots.filter(robot => {
return robot.name.toLowerCase().includes(this.state.searchfield.toLowerCase());
})
return (
<div className="container text-center mt-4">
<h1 className="custom mb-5">RoboFriends</h1>
<input onChange={this.onSearchChange} />
<pre>{JSON.stringify(filteredRobots, null, 2)}</pre>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I solved the problem by appending () to response.json:
return response.json();
Check the data type of users below: You are reassigning robots object with users and which should be array, if you want to access filter method. I think you data type of users i not array and that is why its throwing error. try printing users in console.
.then((users) => {
console.log(users);
this.setState({robots: users});
})
and correct below json() method in your code.
return response.json();
you should use fetch rest calling like that
fetch("https://jsonplaceholder.typicode.com/users").then(res => {
res.json().then(users => {
this.setState({ robots: users });
});
});
It should work.
response.json is a promise so you have to call with () something like this.
import React from 'react';
class App extends React.Component {
constructor() {
super()
this.state = {
robots: [],
searchfield: ''
}
}
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/users').then(response => {
return response.json();
}).then((users) => {
this.setState({ robots: users });
})
}
onSearchChange = (event) => {
this.setState({ searchfield: event.target.value });
}
render() {
const filteredRobots = this.state.robots.filter(robot => {
return robot.name.toLowerCase().includes(this.state.searchfield.toLowerCase());
})
return (
<div className="container text-center mt-4">
<h1 className="custom mb-5">RoboFriends</h1>
<SearchBox searchChange={this.onSearchChange} />
<CardList robots={filteredRobots} />
</div>
);
}
}
export default App;
refer this link : https://www.robinwieruch.de/react-fetching-data
I have 3 components. App.js - Main. localLog.jsx stateless, LoadBoard.jsx statefull. I want to Take string of data from LoadBoard and display it in localLog.jsx. The problem is that I can't figure it out why LocalLog is not displaying on screen.
console.log(this.data.Array) in App.jsx localLog is ["configuration"]
(2) ["configuration", "It's good configuration"]
App.jsx
class App extends Component {
constructor(props) {
super(props);
this.dataArray = [];
this.state = {
headers: []
};
this.localLog = this.localLog.bind(this);
}
localLog(data) {
if (data) {
this.dataArray.push(data);
console.log(this.dataArray);
this.dataArray.map(data => {
return <LocalLog info={data} />;
});
}
}
render() {
return (
<>
<LoadBoard apiBase={this.state.apiBase} localLog={this.localLog} />
<pre id="log_box">{this.localLog()}</pre>
</>
);
}
}
localLog.jsx
let localLog = props => {
return (
<pre className={classes.background}>
<ul className={classes.ul}>
<li>{props.info}</li>
<li>hello world</li>
</ul>
</pre>
);
};
export default localLog;
LoadBoard.jsx
class LoadBoard extends Component {
constructor(props) {
super(props);
this.state = {
positionToId: []
};
}
componentDidMount() {
this.props.localLog("configuration");
this.props.localLog(`It's good configuration`);
}
render() {
return (
<div>
<h1>Nothing interesting</h1>
</div>
);
}
}
You are not returning anything from the localLog method, should be:
return this.dataArray.map(data => {
return <LocalLog info={data} />;
});
EDIT:
here is what your App component should look like.
class App extends Component {
constructor(props) {
super(props);
this.state = {
headers: [],
logs: []
};
this.addLog = this.addLog.bind(this);
}
// Add log to state
addLog(log) {
this.setState(state => ({
...state,
logs: [...state.logs, log]
}));
}
render() {
return (
<>
<LoadBoard apiBase={this.state.apiBase} localLog={this.addLog} />
<pre id="log_box">
{this.state.logs.map(log => {
return <LocalLog info={log} />;
})}
</pre>
</>
);
}
}
you should use setState method in order to re-render the component.
you can try this.
class App extends Component {
constructor(props) {
super(props);
this.state = {
headers: [],
dataArray: []
};
this.localLog = this.localLog.bind(this);
}
localLog(data) {
if (data) {
this.state.dataArray.push(data);
this.setState({dataArray: this.state.dataArray})
}
}
render() {
return (
<>
<LoadBoard apiBase={this.state.apiBase} localLog={this.localLog} />
<pre id="log_box">{this.state.dataArray.map(i => <LoaclLog info={i}/>)}</pre>
</>
);
}
}
I have the following structure of components in the application:
class Car extends Component {
constructor() {
super();
this.state = {
cars: [],
...
}
}
componentDidMount() {
axios.get('/api/cars')
.then((response) => {
this.setState({cars: response.data});
console.log('cars: ', cars);
}).catch(err => {
console.log('CAUGHT IT! -> ', err);
});
}
render() {
return (
...
<CarAddNew />
<CarSearch />
<CarList cars={this.state.cars} />
)
}
}
and then
export default class CarSearch extends Component {
constructor(){...}
handleSearchSubmit(e) {
e.preventDefault();
..
axios.post('/api/cars/search', searchCars)
.then(response => {
console.log('response.data: ', response.data);
})
}
render() {
return(
... search form ...
)
}
When I search data in the database through the CarSearch component, it will fetch and load the right data, that's great. However, how do I pass this "new" found data to the CarList component, so I can display the on the page?
What I would do is the following:
class Car extends Component {
constructor() {
super();
this.state = {
cars: [],
...
}
}
componentDidMount() {
axios.get('/api/cars')
.then((response) => {
this.setState({cars: response.data});
console.log('cars: ', cars);
}).catch(err => {
console.log('CAUGHT IT! -> ', err);
});
}
handleSearch = () => {
axios.post('/api/cars/search', searchCars) // not sure where you are getting searchCars from, but you should get the idea
.then(response => {
this.setState({cars: response.data})
console.log('response.data: ', response.data);
})
}
render() {
return (
...
<CarAddNew />
<CarSearch onSearch={this.handleSearch} />
<CarList cars={this.state.cars} />
)
}
}
export default class CarSearch extends Component {
constructor(){...}
handleSearchSubmit(e) {
e.preventDefault();
this.props.onSearch() // I'm assuming you probably want to pass something here
}
render() {
return(
... search form ...
)
}
One option is to propagate the data up through a prop on CarSearch. Consider the (truncated) example...
handleSearchSubmit(e) {
e.preventDefault();
axios.post('/api/cars/search', searchCars).then(response => {
this.props.onData(response.data);
});
}
where, onData calls back up to the following (then later setting state)...
constructor() {
// [...]
this.onSearchResult = this.onSearchResult.bind(this);
}
onSearchResult(cars) {
this.setState({cars}); // results from CarSearch
}
render() {
return (
<CarAddNew />
<CarSearch
onData={this.onSearchResult} />
<CarList
cars={this.state.cars} />
)
}