Reputation: 167
Trying to create a new Note in "Create" component sent a POST request and added it to the database. Now I need the change to be reflected in the state of "App" component.
Solution: On submission of Note (Create Comp) to the database, a copy of the object is sent to App.js, where we update note property in state so that it reflects the change in the database.
Issue: Getting a few errors, problem lines are labeled in the code.
class App extends Component{
state = {
notes: []
}
componentDidMount(){
fetch('http://localhost:3001/notes')
.then(resp => resp.json())
.then(data => this.setState({notes: data}))
}
onSubmitUpdateState(newNote){
const oldState = [...this.state.notes]
// Problem 2)
this.setState({notes: [...oldState, newNote]});
}
render(){
return(
<div className="App">
<Notes notes={this.state.notes}/>
<Create updateState={this.onSubmitUpdateState}/>
</div>
)
}
}
export default App;
import React, { Component } from 'react';
import classes from './Create.module.css';
class Create extends Component{
state= {
title: "",
body: ""
}
onChange = (e)=>{
this.setState({[e.target.name]: e.target.value})
}
handleSubmit = (e)=>{
e.preventDefault();
const post = {
title: this.state.title,
body: this.state.body
}
// Problem 1
fetch('http://localhost:3001/notes', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(post)
})
.then(res => res.json())
.then(data => this.props.updateState(data))
this.setState({
title: "",
body: ""
})
}
render(){
return (
<div className={classes.CreateContainer}>
<div className={classes.Create}>
<h1>Create</h1>
<form onSubmit={this.handleSubmit}>
<label>Title:</label><br/>
<input type="text" name="title" onChange={this.onChange} value={this.state.title}></input><br/>
<label>Body:</label><br/>
<textarea row="8" col="50" name="body" onChange={this.onChange} value={this.state.body}></textarea><br/>
<input type="submit" value="Submit"></input>
</form>
</div>
</div>
)
}
}
export default Create;
Upvotes: 0
Views: 348
Reputation: 12174
In Javascript, class methods are not bounded by default, this SO answer talks about why is it like that?
If you're not using arrow function, make sure to bind()
your event handlers to access this
.
<Create
updateState={this.onSubmitUpdateState.bind(this)} // pass a binded handler
/>
Upvotes: 2
Reputation: 324
Use Arrow function or bind your action, if you are using this.state in any of method.
Arrow Function :
onSubmitUpdateState = (newNote) => {
const oldState = [...this.state.notes]
// Problem 2)
this.setState({notes: [...oldState, newNote]});
}
bind method : Create constructor and add this line in your constructor
this.onSubmitUpdateState = this.onSubmitUpdateState.bind(this)
Without constructor
<Create updateState={this.onSubmitUpdateState.bind(this)}/>
Upvotes: 3
Reputation: 4150
The error is complaining that this.state
is undefined, you may need to pass the function this.onSubmitUpdateState
as arrow function
I am not sure though why is this not bounded when function passed as props
<Create updateState={()=> this.onSubmitUpdateState()}/>
there is another answer that explains why is it happening so.
Upvotes: 1
Reputation: 3690
Try doing this
class App extends Component{
state = {
notes: []
}
componentDidMount(){
fetch('http://localhost:3001/notes')
.then(resp => resp.json())
.then(data => this.setState({notes: data}))
}
onSubmitUpdateState = (newNote) => { //change to arrow function//
const oldState = [...this.state.notes]
// Problem 2)
this.setState({notes: [...oldState, newNote]});
}
render(){
return(
<div className="App">
<Notes notes={this.state.notes}/>
<Create updateState={this.onSubmitUpdateState}/>
</div>
)
}
}
export default App;
The arrow syntax takes care of the this
binding for you. Or you can bind
the function inside constructor. `
Basically arrow functions preserve this
context when they are called
Upvotes: 1