Reputation: 93
I want to removing TodoItem by clicking on TodoItem, but React returns "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.". It is returned because my on click function is called on mount, keyup on input or after clicking Add button and I completely don't know why it works in this way.
App.js (component)
class App extends Component {
render() {
return (
<BrowserRouter>
<div className="App">
<Header/>
<div className="container">
<div className="row">
<InputContainer/>
</div>
<TodosList todos={this.props.todos}/> {}
</div>
</div>
</BrowserRouter>
);
}
}
const mapStateToProps = state => {
return {
todos: state.todos
};
};
const mapDispatchToProps = {};
export const AppContainer = connect(mapStateToProps, mapDispatchToProps)(App);
TodosList.js (component)
import * as React from "react";
import { connect } from "react-redux";
import { TodoItem } from "./TodoItem"
import { handleRemoveTodo } from "./actions"
export class TodosListC extends React.Component{
todoToTodoItem = todo => {
return <TodoItem key={todo.id} todo={todo} onClick={this.removeTodo(todo.id)}/>
};
render(){
return(
<ul className='col-sm-6 col-sm-offset-3'>
{this.props.todos.map(this.todoToTodoItem)}
</ul>
)
}
removeTodo = e => {
this.props.handleRemoveTodo(e);
}
}
const mapStateToProps = state => {
return {
todos: state.todos,
newInput: state.newInput
};
};
const mapDispatchToProps = { handleRemoveTodo };
export const TodosList = connect(mapStateToProps, mapDispatchToProps)(TodosListC);
Todos.js (reducer)
export const todos = (state = initState, action) => {
switch (action.type) {
case 'HANDLE_SAVE_VALUE':
return [
...state,
{
id: action.id,
name: action.text
}
]
case 'HANDLE_REMOVE_TODO':
//firing on input keyup, click submit button and component mount
console.log('HANDLE_REMOVE_TODO',action.id)
var newState = state.filter(function(todo) {
return action.id !== todo.id
});
return[
newState
]
default:
return state
}
}
const initState =
[{id:99998, name: 'Todo99998'},{id:99999, name:'Todo99999'}]
Link to project zip Link
Thanks in advance for your help.
Upvotes: 1
Views: 1057
Reputation: 336
I have cleaned up the code little bit, there was a misconfiguration of mapToProps and unwanted methods, I have removed those this will remove element on click yet you need to fix few stuff in reducer to remove specific data. Best of luck
////TodoListC.js
import * as React from "react";
import {
connect
} from "react-redux";
import {
bindActionCreators
} from "redux";
import {
TodoItem
} from "./TodoItem"
import {
handleRemoveTodo
} from "./actions"
export class TodosListC extends React.Component {
render() {
return ( <
ul className = 'col-sm-6 col-sm-offset-3' > {
this.props.todos.map((todo) => < TodoItem key = {
todo.id
}
id = {
todo.id
}
todo = {
todo
}
handleRemoveTodo = {
this.props.handleRemoveTodo
}
/>)} <
/ul>
)
}
}
const mapStateToProps = state => {
return {
todos: state.todos,
newInput: state.newInput
};
};
const mapDispatchToProps = dispatch => bindActionCreators({
handleRemoveTodo
}, dispatch)
export const TodosList = connect(mapStateToProps, mapDispatchToProps)(TodosListC);
////TodoItem.js
import * as React from "react";
export const TodoItem = ({ todo, id, handleRemoveTodo}) => {
return(
<li key={id} onClick={() => handleRemoveTodo(id)}>{todo.name}</li>
)
};
Upvotes: 0
Reputation: 5747
You're executing the function on render here
<TodoItem ... onClick={this.removeTodo(todo.id)}/>
onClick
expects a function, but you're calling another function inside of removeTodo
and returning nothing, so to fix your code you could just re-write it as something like this
<TodoItem ... onClick={() => this.removeTodo(todo.id)} />
Upvotes: 1
Reputation: 336
Update todoToTodoItem method will fix this error :
todoToTodoItem = todo => {
return <TodoItem key = {
todo.id
}
todo = {
todo
}
onClick = {
() => this.removeTodo(todo.id)
}
/>
};
Upvotes: 0