Reputation: 85
I'm start learning Reactjs, and i try to made my first app (To-do-List), i want help in how to make Strike-through on the completed task when i click the button
//index.js
import axios from 'axios'
import React, { Component } from 'react';
import logo from './logo.svg';
import loading from './loading.gif'
import './App.css';
import ListItem from './listItem';
class App extends Component {
constructor() {
super();
this.state = {
newTodo: '',
isEmpty: false,
editing: false,
editingIndex: null,
nofication :null,
notifyFlag : false,
notifyEditFlag :false,
loading : true,
finish : false,
todos: []
};
this.apiUrl = 'https://5d87dcecfeddff0014e1568d.mockapi.io'
this.addTodo = this.addTodo.bind(this);
this.updateTodo = this.updateTodo.bind(this);
this.deleteTodo = this.deleteTodo.bind(this);
this.handleChange = this.handleChange.bind(this);
// this.generateTodoId = this.generateTodoId.bind(this);
this.displayNofication = this.displayNofication.bind(this);
this.doneTodo = this.doneTodo.bind(this);
}
async componentDidMount() {
const response = await axios.get(`${this.apiUrl}/todos`);
setTimeout(()=>{
this.setState({
todos: response.data,
loading : false
});
},1000)
}
async doneTodo(item, index){
console.log(item.name.strike());
const todo = this.state.todos[index];
const response = await axios.put(`${this.apiUrl}/todos/${todo.id}`,{
})
this.setState({
finish : true,
})
}
handleChange(event) {
this.setState({
newTodo: event.target.value
});
if (/^[\s]*([a-zA-Z0-9]+[\s]*)*$/.test(event.target.value)) {
this.setState({
isEmpty : true
})
} else {
this.setState({
isEmpty : false
})
}
}
// generateTodoId() {
// const lastTodo = this.state.todos[this.state.todos.length - 1];
// if (lastTodo) {
// return lastTodo.id + 1;
// }
// return 1;
// }
async addTodo() {
if(this.state.isEmpty){
// const newTodo = {
// name: this.state.newTodo,
// id: this.generateTodoId()
// };
const response = await axios.post(`${this.apiUrl}/todos`, {
name: this.state.newTodo
});
const todos = this.state.todos;
todos.push(response.data);
this.setState({
todos: todos,
newTodo: '',
isEmpty :false,
nofication:this.displayNofication(),
notifyFlag:true
});
this.displayNofication("todo added successfuly")
}
}
editTodo(index) {
const todo = this.state.todos[index];
this.setState({
editing: true,
newTodo: todo.name,
editingIndex: index,
notifyEditFlag :true,
});
}
async updateTodo() {
this.setState({
loading : true
})
const todo = this.state.todos[this.state.editingIndex];
const response = await axios.put(`${this.apiUrl}/todos/${todo.id}`,{
name : this.state.newTodo
})
// todo.name = this.state.newTodo;
const todos = this.state.todos;
todos[this.state.editingIndex] = response.data;
setTimeout(()=>{
this.setState({
todos,
editing: false,
editingIndex: null,
newTodo: '',
loading : false
});
},1000)
this.displayNofication("todo update successfuly");
}
async deleteTodo(index) {
const todos = this.state.todos;
const todo = todos[index]
await axios.delete(`${this.apiUrl}/todos/${todo.id}`)
delete todos[index];
this.setState({
todos,
notifyFlag:false
});
this.displayNofication("todo deleted successfuly")
}
displayNofication(notify){
this.setState({
nofication :notify
})
setTimeout(()=>{
this.setState({
nofication : null,
notifyEditFlag:false
});
}, 2000)
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">CRUD React</h1>
</header>
<div className="container">
{
this.state.notifyEditFlag ? this.state.nofication&&<div className="alert mt-3 alert-info"><p>{this.state.nofication}</p></div>:this.state.notifyFlag ? this.state.nofication&&<div className="alert mt-3 alert-success"><p>{this.state.nofication}</p></div>:this.state.nofication&&<div className="alert mt-3 alert-danger"><p>{this.state.nofication}</p></div>
}
<input
type="text"
name="todo"
className="my-4 form-control"
placeholder="Add a new todo"
onChange={this.handleChange}
value={this.state.newTodo}
/>
<button
onClick={this.state.editing ? this.updateTodo : this.addTodo}
className="btn-info mb-3 form-control">
{this.state.editing ? 'Update todo' : 'Add todo'}
</button>
{
this.state.loading&& <img src={loading} alt="loading Gif"/>
}
{
!this.state.editing &&
<ul className="list-group">
{this.state.todos.map((item, index) => {
return <ListItem
key={item.id}
item={item}
finish={this.state.finish}
editTodo={()=>{this.editTodo(index);}}
deleteTodo={()=>{this.deleteTodo(index);}}
doneTodo={()=>{this.doneTodo(index);}}
/>
})}
</ul>
}
</div>
</div>
);
}
}
export default App;
listItem.js
import React from 'react';
const ListItem = (props) => {
return <li className="list-group-item">
<button
className="btn-sm mr-4 btn btn-info"
onClick={props.editTodo}
>U</button>
{props.finish ? <strike>{props.item.name}</strike>: `${props.item.name}`}
<button
className="btn-sm ml-4 btn btn-danger"
onClick={props.deleteTodo}
>X</button>
<button className="btn-sm ml-4 btn btn-info" onClick={props.doneTodo}>Done!</button>
</li>;
};
export default ListItem;
when i clicked button Done! it make all tasks as completed, i only need specific index (li)tag that i clicked the button done in, so you any one could help me to handel it
Upvotes: 0
Views: 455
Reputation: 2558
What you're trying to achieve is,
- Storing the state of a ToDo in
finish
flag.- When a ToDo is marked 'Done', you're updating the
finish
flag.
Points to keep in mind -
prop
or state
changes, the component will re-render.finish
.This is what's happening in your code:
- You click on Done for any ToDo item.
- Control goes to
doneTodo
and an axios PUT call is made.- After that, state variable
finish
is updated.- Since state is updated, your
App
component renders again.- During the render, for every
ListItem
, afinish
value of true is passed from state.- So every ToDo item, is rendered as Done.
To fix the issue, you could choose to have a state finishStatus
as array (similar to todos
), and update the array index when a Done is clicked (Also need to pass respective value to finish
prop of ListItem
.
Something like this - https://codesandbox.io/embed/react-basic-todo-stack-58086171-xkt5t
Upvotes: 1