-1

i am beginner for react and i have 3 questions 1)How can i prevent creating blank tasks(see attached image)

2)how to add strikethrough for checked tasks for UI?

3)why i'm getting this error

Warning: Each child in a list should have a unique "key" prop.

my react code :

import React from "react";
import "./styles.css";
let id = 0
const Todo = props => (
  <li>
    <input type="checkbox" checked={props.todo.checked} onChange={props.onToggle} />
    <button onClick={props.onDelete}>delete</button>
    <span>{props.todo.text}</span>
  </li>
)
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      todos: [],
    }
  }
  addTodo() {
    const text = prompt("TODO text please!")
    this.setState({
      todos: [
        ...this.state.todos,
        {id: id++, text: text, checked: false},
      ], 
    })
  }
  removeTodo(id) {
    this.setState({
      todos: this.state.todos.filter(todo => todo.id !== id)
    })
  }
  toggleTodo(id) {
    this.setState({
      todos: this.state.todos.map(todo => {
        
        if (todo.id !== id) return todo
        return {
          id: todo.id,
          text: todo.text,
          checked: !todo.checked,
        }
      })
    })
  }
  render() {
    return (
      <div>
        <div>Todo count: {this.state.todos.length}</div>
        <div>Unchecked todo count: {this.state.todos.filter(todo => !todo.checked).length}</div>
        <button onClick={() => this.addTodo()}>Add TODO</button>
        <ul>
          {this.state.todos.map(todo => (
            <Todo
              onToggle={() => this.toggleTodo(todo.id)}
              onDelete={() => this.removeTodo(todo.id)}
              todo={todo}
             
            />
          ))}
        </ul>
      </div>
    )
  }
}
export default App;

result: todo-list result image

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Rookie
  • 1
  • 1
  • 4
  • 2
    Welcome to SO! I would definitely encourage googling errors (or even searching on SO) as `Warning: Each child in a list should have a unique "key" prop.` is a very common error that people run into in React when rendering a collection. This answer https://stackoverflow.com/questions/28329382/understanding-unique-keys-for-array-children-in-react-js/43892905#43892905 goes into great detail about the `key` prop. – Anthony Jun 22 '20 at 21:04

3 Answers3

0
  1. How can I prevent creating blank tasks(see attached image)

You will have to check that text is not an empty string before creating the task

  addTodo() {
    const text = prompt("TODO text please!")
    if(text !=== ""){ // <- check here
      this.setState({
        todos: [
          ...this.state.todos,
          {id: id++, text: text, checked: false},
        ], 
      })
    }
  }
  1. how to add strikethrough for checked tasks for UI?

this can be done easily whit css using text-decoration: line-through;, so, create a class with that property (or you can do it inline also) and if the state of the task is done, add that class to the component

.text-strike {
  text-decoration: line-through;
}


<Todo className={checked ? 'text-strike' : null}}
  1. why i'm getting this error

Every time you loop through an array to create views, React needs something to tell all the components from each other apart so when the times comes to update one of them in the UI (re-render) it knows exactly which one it should update thus increasing performance

  {this.state.todos.map(todo => (
     <Todo
        onToggle={() => this.toggleTodo(todo.id)}
        onDelete={() => this.removeTodo(todo.id)}
        todo={todo}
        key={somethingUnique}  // <- you need to add this key
     />
  ))}
ludwiguer
  • 2,177
  • 2
  • 15
  • 21
0
  1. in the addTodo function add a validation for empty todo like below
addTodo() {
    const text = prompt("TODO text please!")
    if(text === undefined || text === "" || text?.trim() === ""){
    alert("You are lazy!!! enter proper value.");
    }else{
    this.setState({
      todos: [
        ...this.state.todos,
        {id: id++, text: text, checked: false},
      ], 
    })
    }

  }
  1. for striking wrap text with <s> tag
  2. your reacts rendering mechanism needs to differentiate elements and it uses key as a differentiator to easily update any changes made to that element in your for loop, as dom doesn't speak for loop it's react that does for you and that's sort of interface for react to understand that it has to maintain it. Hence add a key to your todo list as below
 <Todo
              onToggle={() => this.toggleTodo(todo.id)}
              onDelete={() => this.removeTodo(todo.id)}
              todo={todo}
             key = {todo.id}
            />
pavan kumar
  • 823
  • 6
  • 15
0

See corrections with the comments:

import React from 'react';

let id = 0;
const Todo = (props) => (
   // style based on props
  <li style={{ textDecoration: props.todo.checked ? 'line-through' : ''}}>
    <input
      type='checkbox'
      checked={props.todo.checked}
      onChange={props.onToggle}
    />
    <button onClick={props.onDelete}>delete</button>
    <span>{props.todo.text}</span>
  </li>
);

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      todos: [],
    };
  }
  addTodo() {
    const text = prompt('TODO text please!');
    // only do this if text has value
    text && this.setState({
        todos: [...this.state.todos, { id: id++, text: text, checked: false }],
      });
  }
  removeTodo(id) {
    this.setState({
      todos: this.state.todos.filter((todo) => todo.id !== id),
    });
  }
  toggleTodo(id) {
    this.setState({
      todos: this.state.todos.map((todo) => {
        if (todo.id !== id) return todo;
        return {
          id: todo.id,
          text: todo.text,
          checked: !todo.checked,
        };
      }),
    });
  }
  render() {
    return (
      <div>
        <div>Todo count: {this.state.todos.length}</div>
        <div>
          Unchecked todo count:{' '}
          {this.state.todos.filter((todo) => !todo.checked).length}
        </div>
        <button onClick={() => this.addTodo()}>Add TODO</button>
        <ul>
          {this.state.todos.map((todo) => (
            <Todo
              key={todo.id} // need a unique key using id
              onToggle={() => this.toggleTodo(todo.id)}
              onDelete={() => this.removeTodo(todo.id)}
              todo={todo}
            />
          ))}
        </ul>
      </div>
    );
  }
}
export default App;
SakoBu
  • 3,972
  • 1
  • 16
  • 33