I have reactJS class when I get a data in JSON and try to trasfrom it for html:
class ProjectList extends React.Component {
constructor(props) {
super(props);
this.state = {projects: []};
}
componentDidMount() {
axios
.get('http://localhost:8080/project')
.then(res => this.setState({ projects: res.data.name }))
.catch(err => console.log(err))
}
render() {
return (
this.state.projects.map((project) => {
return (
<div>
<p> {project.name} </p>
</div>
)
})
)
}
}
ReactDOM.render(
<ProjectList />,
document.getElementById('root')
);
I can undestand what is problem because have some problem with reactJS
Looks like you are storing res.data.name instead of res.data. Meaning this.state.projects is getting set to a single name string. You should be setting this.state.projects to res.data to get the full array of projects:
componentDidMount() {
axios
.get('http://localhost:8080/project')
.then(res => this.setState({ projects: res.data }))
.catch(err => console.log(err))
}
Related
Components
const Pcards = ({ projects }) => {
return (
<div>
<CardColumns>
{projects.map((projects) => (
<Card>
<Card.Img variant="top" src={"http://localhost:8000" + projects.images[0].file_path + projects.images[0].file_name + projects.images[0].file_type} />
Pages
class Projects extends Component {
state = {
projects:[]
}
componentDidMount() {
fetch('http://localhost:5000/api/projects')
.then(res => res.json())
.then((data) => {
this.setState({ projects: data })
})
.catch(console.log)
}
render () {
return (
<Pcards projects = {this.state.projects} />
);
}
}
New to react and this code returns
TypeError: projects.map is not a function
This appears to be compiling just fine on my partner's end since he written this code and I'm trying to expand on his work.
I've seen other similar posts but unable to find a fix. Any idea what's going on here?
You have two mistakes in your Projects class.
1- .catch error handling syntax was wrong
2- you were not checking the fetched data
class Projects extends Component {
state = {
projects: []
}
componentDidMount() {
fetch('http://localhost:5000/api/projects')
.then(res => res.json())
.then((data) => {
if (data && data.length) { // checking the data
this.setState({ projects: data })
} else {
console.log("Projects fetch failed, check your api code!")
}
})
.catch(e => console.log(e)); // corrected error catch
}
render() {
return (
<Pcards projects={this.state.projects} />
);
}
}
You can also edit your Pcards component code. You are already using a property called projects and you are mapping it, calling the argument projects too. That is not a good practice. If you are mapping projects name the item as project or projectItem.
projects.map((project) => ...
Try
class Projects extends Component {
constructor(props){
super(props)
this.state = {
projects:[]
}
}
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}/>} />
I have a component that is a select box, i added an onChange to the select box to "capture" its data and set it to a variable in state. I then try to pass it as props to another component [i.e the "display component"] then i use this.props at the end of a new fetch call in the display component to display the data.........it doesn't work. Please Help.
class Test extends Component {
constructor(props) {
super(props)
this.state = {
routes: [],
vessel: ''
}
this.makeChange = this.makeChange.bind(this)
}
componentDidMount() {
fetch(`http://localhost:5000/routes`)
.then(res => res.json())
.then(data => this.setState({
routes: data
}))
}
makeChange(event) {
this.setState({
vessel: event.target.value
})
}
render() {
let { routes } = this.state
return (
<>
<select onChange={this.makeChange}>
<option>Select A Vessel</option>
{routes.map(vessel => {
return (
<option key={uuidv4()}>{vessel.vessel}</option>
)
})}
</select>
<VRoute vessel={this.state.vessel} />
</>
)
}
}
}
-----------------------DISPLAY COMPONENT BELOW-------------------------------
class VRoute extends Component {
constructor(props) {
super(props)
this.state = {
routes: [],
}
}
componentDidMount() {
fetch(`http://localhost:5000/routes/${this.props.vessel}`)
.then(res => res.json())
.then(data => this.setState({
routes: data
}))
}
render() {
let { routes } = this.state;
return ( <table>
<tbody>
</tr>
{routes.map(value => {
return (
<tr key={uuidv4()}>
<td>{value.departure_port}</td>
<td>{value.arrival_port}</td>
<td>{value.departure_time}</td>
<td>{value.arrival_time}</td>
<td>{value.date_stamp}</td>
<td>{value.price}</td>
<td><button className='delete-btn'>x</button></td>
</tr>
)
})}
</tbody>
Try this:
<select onChange={this.makeChange}>
<option>Select A Vessel</option>
{routes.map(vessel => {
return (
<option key={uuidv4()} value={vessel.vessel}>{vessel.vessel}</option>
)
})}
</select>
<VRoute vessel={this.state.vessel} />
</>
Display component..
componentWillUpdate(nextProps) {
if (nextProps.vessel !== this.state.vessel) {
this.setState({vessel: nextProps.vessel}, () => {
fetch(`http://localhost:5000/routes/${this.state.vessel}`)
.then(res => res.json())
.then(data => this.setState({
routes: data
}))
})
}
}
I am working on a hacker news clone I am trying to get the ids of the top stories from their api using axios in componentDidMount and then making another axios call to get the stories and push them in a state array but when I try to map over and render that array nothing shows up
class App extends Component {
constructor(props) {
super(props);
this.state = {
posts: []
}
}
componentDidMount() {
axios.get('https://hacker-news.firebaseio.com/v0/topstories.json')
.then( result => {
result.data.slice(0, 10).forEach(element => {
axios.get('https://hacker-news.firebaseio.com/v0/item/' + element + '.json')
.then( value => {
this.state.posts.push(value)
})
.catch(err =>{
console.log(err)
})
})
})
.catch(err => {
console.log(err);
})
}
render() {
return (
<div>
<Header title="Hacker News" />
{this.state.posts.map( (element, index) => <Post key={element.data.id} serialNum={index} postTitle={element.data.title} postVotes={element.data.score} postAuthor={element.data.by} />) }
</div>
)
}
}
Try setting the state like this:
axios.get('https://hacker-news.firebaseio.com/v0/item/' + element + '.json')
.then( value => {
this.setState({
posts: [value, ...this.state.posts]
})
})
.catch(err =>{
console.log(err)
})
})
This way you're using setState and appending every new value to the existing state.
As stated in the comments, don't use push for set state. In your code when you make the second request you must change the setState method to spread out the new value.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
posts: []
}
}
componentDidMount() {
axios.get('https://hacker-news.firebaseio.com/v0/topstories.json')
.then( result => {
result.data.slice(0, 10).forEach(element => {
axios.get('https://hacker-news.firebaseio.com/v0/item/' + element + '.json')
.then( value => {
this.setState(prevState => ({posts: [ value.data, ...prevState.posts]}))
})
.catch(err =>{
console.log("err");
console.log(err);
})
})
})
.catch(err => {
console.log(err);
})
}
render() {
return (
<div>
{this.state.posts && this.state.posts.map( (element, index) =>
<div key={element.id}>
{element.title}
</div>
)}
</div>
);
}
}
componentDidMount() is called after Render() only once. React doesn't know about the state changes unless you use setState().
componentDidMount() {
axios.get('https://hacker-news.firebaseio.com/v0/topstories.json')
.then( result => {
result.data.slice(0, 10).forEach(element => {
axios.get('https://hacker-news.firebaseio.com/v0/item/' + element + '.json')
.then( value => {
this.setState({posts: [value, ...this.state.posts]})
})
})
})
}
Use this.setState({posts : [value, ...this.state.posts]}) instead of this.state.posts.push(value). using ... (spread operator) appends the value to the original posts array.
I am using the componentDidUpdate() method and for the most part, it is doing what it should. It runs the function to get the data from the API as well as logs it to the console. The problem is that it does not render the new data on the front end. The only time it renders the new data is if the component actually mounts (if the page is refreshed). I feel like I'm very close, but have hit a dead end. Here is my code:
import React from 'react';
import Nav from './Nav';
class List extends React.Component {
constructor(props) {
super(props);
this.state = {
APIData: []
}
}
getAPIData() {
const url = `http://localhost:3001${this.props.location.pathname}`;
return fetch(url, {
method: 'GET',
mode: 'CORS',
headers: {
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => {
console.log(data);
return data;
}).catch(err => { console.log('Error: ', err) });
};
dataList() {
return (
<div>
{this.state.APIData.map((APIData) => (
<p> And the data returned is -> {APIData.firstName}
{APIData.lastName} !</p>
)
)}
</div>
)
}
componentDidMount() {
console.log(this.props.location.pathname);
this.getAPIData()
.then(data => {
console.log('in List.js ', data);
this.setState({
APIData: data
});
});
}
componentDidUpdate(prevProps, prevState) {
console.log(this.props.location.pathname);
// only update if the data has changed
this.getAPIData()
.then(data => {
if (prevProps.data !== this.props.data) {
this.setState({
APIData: data
});
}
console.log(data);
});
}
render() {
return (
<div>
<Nav />
<br />
<br />
<br />
<br />
<div>
{/* {this.state.APIData.map((APIData) => (
<p> And the data returned is -> {APIData.firstName}
{APIData.lastName} !</p>
)
)} */}
{this.dataList()}
</div>
</div>
);
}
}
export default List;
I think it may be this block:
if (prevProps.data !== this.props.data) {
this.setState({
APIData: data
});
}
Are you actually passing a data prop to this component?
If not, then it would be checking if undefined !== undefined and never executing.
If you are, then you might check if the data reference is actually changing, or you're just mutating the inside of the object.