santoku
santoku

Reputation: 3427

How to create a to-do list in React without ref

I intend to create a to-do list without using ref as in the many examples, but it isn't working.

The expected behavior is that upon entering an entry, it will show up at the top and upon clicking add, it will create an input box for entering an entry. Currently, upon entering the state returns undefined.

The code can be found below or in this sandbox:

import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
import ToDo from './todo'
class App extends Component {
  constructor() {
    super();
    this.state = {
      todos: []
    };
  }

  onChange=(e)=>{
    const newToDos = [...this.state.todos]
    newToDos.push(e.target.value)
    this.setState({
      todos: newToDos
    })
  }

    onAdd=(e)=>{
      e.preventDefault();
      const newtodos=[...this.state.todos]
      this.setState({
        todos: newtodos.push("")
      })
  }

  render() {
    console.log(this.state.todos)
    return (
      <div>
        <p>All the to-dos include {this.state.todos}</p>
        <ToDo 
          todos={this.state.todos}
        />
        <form onSubmit={this.onChange}>
          <input 
            type="text" 
            placeholder="add a new todo..."
          />
        </form>   
        <button onClick={this.onAdd}>+</button>
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

And here is the todo.js:

import React, { Component } from 'react';
import { render } from 'react-dom';

export default class ToDo extends Component {
  constructor(props){
    super(props)
  }

  render() {
    const {todos, onChange}=this.props
    return (
      <div>
        {
          todos.map((todo, index)=>
          <div>
            {todo}
          </div>
          )
        }
      </div>
    );
  }
}

Upvotes: 0

Views: 1396

Answers (4)

Kamal Pandey
Kamal Pandey

Reputation: 1598

You can update your code with

import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
import ToDo from './todo'
class App extends Component {
  constructor() {
    super();
    this.state = {
      todos: [],
      inputText: ""
    };
  }


    onAdd= () => {
      this.setState({
        todos: [...this.state.todos, this.state.inputText], textInput: ""
      })
  }

  render() {
    console.log(this.state.todos)
    return (
      <div>
        <p>All the to-dos include {this.state.todos}</p>
        <ToDo 
          todos={this.state.todos}
        />
        <form>
          <input 
            type="text" 
            placeholder="add a new todo..."
            onChange={inputText => this.setState({inputText})} 
          />
        </form>   
        <button onClick={this.onAdd}>+</button>
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

And in todo.js you can simply do

import React, { Component } from 'react';
import { render } from 'react-dom';

export default const ToDo = ({todos}) => {
  return(<div>
    {todos.map((todo, index) => (
      <div key={index}>
        {todo}
      </div>))}
    </div>)}

as it do not contains any state associated with it.

Upvotes: 1

ravibagul91
ravibagul91

Reputation: 20755

You have a problem with this code,

<form onSubmit={this.onChange}>
   <input 
       type="text" 
       placeholder="add a new todo..."
   />
</form>   

Here you are adding onSubmit on form, which will never call because you don't have submit button.

you should do something like this,

<form>
 <input 
     type="text" 
     placeholder="add a new todo..."
     onChange={this.onChange}
     value={this.state.currentValue}
 />
</form> 
onChange=(e)=>{
  event.preventDefault();
  this.setState({
      currentValue: e.target.value
  })
}

onAdd=(e)=>{
      e.preventDefault();
      const newToDos = [...this.state.todos]
      newToDos.push(this.state.currentValue)
      this.setState({
         todos: newToDos,
         currentValue: ''
    })
}

Demo

Update

In your todo component you have useless constructor, If you don't have state in a component or don't have any function to bind this don't add constructor.

You can remove the constructor.

Another thing is, you are not passing any onChange prop to todo component, so here you will get undefined for onChange.

const {todos, onChange}=this.props

You can also write this component as a functional component.

Upvotes: 1

kunal verma
kunal verma

Reputation: 486

your code newtodos.push("") dosent return array so no map function:

    this.setState({
    todos: newtodos.push("")
  })

correct it something like this

    this.setState({
        todos: newtodos.concat("new value")
      })

Upvotes: 1

TaiNS
TaiNS

Reputation: 99

You can store your new todo in state when onChange input and add this into todos when click save.

I have forked and edit your sample. https://stackblitz.com/edit/react-nwtp5g?file=index.js

BTW: In your sample, newtodos.push("") will return the length of newtodos array, not the array after pushed.

onAdd=(e)=>{
  e.preventDefault();
  const newtodos=[...this.state.todos]
  this.setState({
    todos: newtodos.push("")
})

Hope this help.

Upvotes: 1

Related Questions