I am trying to pass a function named addtodo as a props from a class. I have passed the function as below
export class Todo extends Component {
constructor(props) {
super(props);
this.state = {todos:[]};
this.addtodo = this.addtodo.bind(this);
this.deleteTodo = this.deleteTodo.bind(this);
}
componentDidMount(){
axios.get('https://jsonplaceholder.typicode.com/posts').then(res=>{
this.setState({
todos:res.data
})
})
}
addtodo(todo){
todo.id=Math.floor(Math.random()*100)
todo.completed=true
const todos=[...this.state.todos,todo]
this.setState({
todos:todos
})
}
deleteTodo(id){
const todo=this.state.todos.filter(todo=>{
return(
todo.id!==id
)
}
)
this.setState({
todos:todo
})
}
render() {
return (
<div>
<h1 className="center-align"> Todos</h1>
<Todolist todos={this.state.todos} deleteTodo={this.deleteTodo}/>
<Addtodo addtodo={this.addtodo}/>
</div>
)
}
}
export default Todo
And in Addtodo.js, I am using the function as props as below
class Addtodo extends Component {
constructor(props) {
super(props);
this.state = { title:'',
body:''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e){
this.setState({
[e.target.id]:[e.target.value]
})
}
handleSubmit(e){
e.preventDefault()
this.props.addtodo(this.state)
this.setState({
title:'',
body:''
})
}
render() {
return (
<form className="col s12" onSubmit={this.handleSubmit}>
<div className="row">
<div className="input-field col s6">
<input placeholder="Add title" id="title" type="text" className="validate" onChange={this.handleChange}/>
</div>
<div className="input-field col s6">
<input placeholder="Add body" id="body" type="text" className="validate" onChange={this.handleChange}/>
</div>
<button type="submit">Submit</button>
</div>
</form>
)
}
}
export default Addtodo
But I am getting the error Uncaught TypeError: this.props.addtodo is not a function
. I checked for spelling error as well but could not get why this is not working. Whereas if I pass it as a props to another class and simply log a hello message it is working.
I successfully run your code on the stackblitz, and there are no errors
and i found another bug,
before
handleChange(e) {
this.setState({
[e.target.id]: [e.target.value]
});
}
after
handleChange(e) {
this.setState({
[e.target.id]: e.target.value
});
}
tip: Because i don't have enough points, so i cannot add comments, can only editor answer
update:
before:
function App() {
return (
<BrowserRouter>
<div className="container">
<Addtodo />
<Switch>
<Route exact path="/" component={Todo} />
<Route path="/:id" component={Task} />
</Switch>
</div>
</BrowserRouter>
);
}
export default App;
function App() {
return (
<BrowserRouter>
<div className="container">
<Switch>
<Route exact path="/" component={Todo} />
</Switch>
</div>
</BrowserRouter>
);
}
render(<App/>, document.getElementById('root'))
Please check the code is not more than one Addtodo?
You're not registering the function addtodo
in the class, thus this.addtodo
is not bound to your function addtodo
but instead to null. Hence your error.
See this example from React docs - Handling events :
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(state => ({
isToggleOn: !state.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
Notice on line 6 the function is first bound to the class, then it can be defined and called through this.<function_name>
.
In your code you're missing in the constructor:
this.addtodo = this.addtodo.bind(this);
Until so, you cannot call this.addtodo
, for it's not bound to this
, thus your error that this.props.addtodo
is not a function.
You're missing binding in your constructor I guess. In your constructor, you need to declare it like this
this.addtodo = this.addtodo.bind(this);
Edited **
I have tested the code and seems like there was no error,
Todo.js
import React, { Component } from "react";
import axios from "axios";
import Addtodo from "./Addtodo";
export class Todo extends Component {
state = {
todos: [],
};
componentDidMount() {
axios.get("https://jsonplaceholder.typicode.com/posts").then((res) => {
this.setState({
todos: res.data,
});
});
}
addtodo = (todo) => {
todo.id = Math.floor(Math.random() * 100);
todo.completed = true;
const todos = [...this.state.todos, todo];
this.setState({
todos: todos,
});
};
render() {
console.log(this.state.todos);
return (
<div>
<h1 className="center-align"> Todos</h1>
<Addtodo addtodo={this.addtodo} />
</div>
);
}
}
export default Todo;
Addtodo.js
import React, { Component } from "react";
class Addtodo extends Component {
constructor(props) {
super(props);
this.state = { title: "", body: "" };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({
[e.target.id]: [e.target.value],
});
}
handleSubmit(e) {
e.preventDefault();
this.props.addtodo(this.state);
this.setState({
title: "",
body: "",
});
}
render() {
return (
<form className="col s12" onSubmit={this.handleSubmit}>
<div className="row">
<div className="input-field col s6">
<input
placeholder="Add title"
id="title"
type="text"
className="validate"
onChange={this.handleChange}
/>
</div>
<div className="input-field col s6">
<input
placeholder="Add body"
id="body"
type="text"
className="validate"
onChange={this.handleChange}
/>
</div>
<button type="submit">Submit</button>
</div>
</form>
);
}
}
export default Addtodo;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.