¿Cómo crear listas (todo list) en react ?


Vamos aprender cómo crear listas (todo list) con  react  con las opciones para agregar y eliminar, el diseño que tenemos es el siguiente:

Puedes ver el ejemplo en el siguiente link o descargar el  repositorio https://github.com/herel/todo-list-example

1.- Analisis de diseño

Después de analizar el diseño  podemos observar que debemos crear los siguientes componentes

  1. Componente  Item  que contiene  los  elementos de la lista como imagen, nombre, precio y el boton de eliminar item que ejecuta una función del componente padre
  2. Componente Button  donde al hacer click añade un nuevo Item a la lista
  3. El componente  padre debe tener la siguientes opciones:
    1. Sumar el precio total de los items
    2. Cuando el usuario hace clic en añadir producto debe agregar un nuevo item a la lista
    3. Si el usuario hace click en eleminar debe quitar el item y actualizar el total del precio

2.- Componente Item

Bien ya analizamos los componentes que vamos a crear ahora es turno de crear el componente item que contiene el siguiente codigo:

import React, { Component } from 'react';

class Item extends Component{
    _remove(){
        if(this.props.onRemove)
            this.props.onRemove();
    }
    render(){
        return (
            <li>
                <div className="icon">
                    <img src={require(`../images/${this.props.data.image}`)}  alt="hambuerger" />
                </div>
                <div className="name">
                    <span className="item-name">{this.props.data.name}</span>
                    <span className="item-price">{this.props.data.portion}</span>
                </div>
                <div className="price">
                    <h3>${this.props.data.price}</h3>
                </div>
                <button className="remove" onClick={this._remove.bind(this)}>
                    <i className="material-icons">close</i>
                </button>
            </li>
        )
    }
}


export default Item;

Como vemos en el componente tenemos un elemento li que contiene el icono, nombre, precio y la opción de eliminar, si el usuario hace clic sobre el boton eliminar se ejecuta la funcion _remove pero solo si en los props viene la función onRemove ejecutamos la funcion del componente padre.

3.- Componente Padre

Ya tenemos el componente Item ahora debemos crear el componente padre que va a importar el componente Item y pasarle los parametros correspondientes.

Vamos a crear el componente con un item de ejemplo como se muestra a continuación

import React, { Component } from 'react';
import Item from './components/Item';
import './App.css';

class App extends Component {

  constructor(props){
    super(props);
    this.state = {
      data : [
        {
          image : "hambuerger.png",
          name  : "Hamburguesa",
          portion : "500g",
          price   : 40
        }
      ]
    }
  }

  _remove(position){
    let { data } = this.state;

    let newData = [
      ...data.slice(0, position),
      ...data.slice(position + 1),
    ]

    this.setState({ data : newData });

  }

  render() {
    return (
      <div className="app">
        <h1>Ejemplo de listas</h1>
        <ul className="todo-list">
          {this.state.data.map(
            (item,index) =>
              <Item data={item} key={index} onRemove={ () => this._remove(index)} />
            )
          }
        </ul>
      </div>
    );
  }
}

export default App;

Que hacemos exactamente en este componente, cuando se crea añadimos al state el arraglo data con 1 elemento de prueba y en el metodo render  recorremos y mostramos los elementos de la lista en caso de que el usuario haga click sobre el boton eleiminar se ejcuta la funcion remove que tiene el siguiente código:

_remove(position){
    let { data } = this.state;
    let newData = [
      ...data.slice(0, position),
      ...data.slice(position + 1),
    ]
    this.setState({ data : newData });
}

¿Que hacemos aqui?

extraemos el array del state, después creamos un nuevo arreglo donde agregamos el arraglo de la posicion 0 hasta donde esta el elemento que vamos a eliminar, despues al mismo arreglo añadimos los elementos que se encuentran depues de la posicion que vamos a eliminar, y por ultimo asignamos el state data con el  nuevo arreglo  que  ya no cuenta con el elemento.

El resultado es el siguiente:

4.- Componente Button

Vamos a crear otro componente para poder añadir mas elementos a la lista, creamos el componente Button

import React, { Component } from 'react';

class Button extends Component{
    
    _add(){
        if(this.props.onClick)
            this.props.onClick();
    }

    render(){
        return (
            <button className="add-button" onClick={this._add.bind(this)}>
                {this.props.name}
            </button>
        )
    }
}

export default Button;

Este component es muy sencillo es un botton donde le pasamos el texto que debe contener si lo queremos reutilizar tambien le podemos pasar la clase para cambair estilos o posición, si el usuario hace click se ejecuta la funcion _add que valida si viene en los props la función onClick

5.- Añadir elementos aleatorios

Si el usuario hace click sobre el boton debemos añadir mas elementos al arreglo, debemos importar el componente y con lodash para sumar el total de los precios.

import React, { Component } from 'react';
import Item from './components/Item';
import Button from './components/Button';
import _ from 'lodash';
import './App.css';

class App extends Component {

  constructor(props){
    super(props);
    this.state = {
      data : [
        {
          image : "hambuerger.png",
          name  : "Hamburguesa",
          portion : "500g",
          price   : 40
        }
      ]
    }
  }

  _remove(position){
    let { data } = this.state;

    let newData = [
      ...data.slice(0, position),
      ...data.slice(position + 1),
    ]

    this.setState({ data : newData });

  }

  _add(){
    let { data } = this.state;
    let newData = [
      ...data,
      {
        image : "papas.png",
        name  : "Papas a la francesa",
        portion : "140g",
        price   : Math.floor(Math.random() * 20) 
      }
    ]
    this.setState({ data : newData });
  }

  _getTotal(){
    return _.sumBy(this.state.data, function(o) { return o.price; });;
  }


  render() {
    return (
      <div className="app">
        <h1>Ejemplo de listas</h1>
        <ul className="todo-list">
          {this.state.data.map(
            (item,index) =>
              <Item data={item} key={index} onRemove={ () => this._remove(index)} />
            )
          }
        </ul>
        <div className="footer">
          <Button
            onClick={this._add.bind(this)}
            name="Añadir producto"
          />
          <h4>$ {this._getTotal()}</h4>
        </div>
      </div>
    );
  }
}

export default App;

el código que se encarga de añadir un nuevo elemento al array es el siguiente:

_add(){
    let { data } = this.state;
    let newData = [
      ...data,
      {
        image : "papas.png",
        name  : "Papas a la francesa",
        portion : "140g",
        price   : Math.floor(Math.random() * 20) 
      }
    ]
    this.setState({ data : newData });
  }

pero que hace exactamente,  bueno extraemos el  array del state, creamos un nuevo array donde le pasamos todo el contenido del array, y añadimos un nuevo objeto con un el precio ramdon de 0 a 20, y por ultimo asignamos la nueva data, el resultado es el siguiente:

Gracias por leer y comentar, aqui algunos libros que me ayudaron a mejorar las buenas practicas a la hora de programar.