Ejercicio entidad bancaria 2.0

Vamos a modificar el ejercicio anterior para añadir la siguiente funcionalidad:

En lugar de tener una variable donde se sumen las entradas y salidas tendremos sendos arrays de objetos donde guardaremos un objeto con la cantidad que hemos sacado y el momento en el que lo hemos hecho.

Al comprobar los límites de retirada o de ingreso lo haremos con respecto a las últimas 24 horas (para las pruebas podemos utilizar un intervalo menor)

En el tema de los ingresos que van a depósito pasadas esas 24 horas se añaden a la cuenta eliminándose de la lista.

Además de todo esto tendremos una lista con las 20 últimas operaciones que se mostrarán por pantalla.

Ejercicio React-Redux: Cuenta Bancaria

Vamos a hacer un ejercicio que simule una cuenta bancaria. Tendrá los siguientes elementos:

Saldo: 5.324,6 €

Cantidad: (input text)

Botones: |Hacer ingreso| |Sacar dinero|

El usuario puede poner una cantidad y si le da hacer ingreso se incrementa el saldo y si le da a sacar dinero se resta.

Con las siguientes condiciones:

Si el ingreso es mayor de 1000 € se suman solo 1000 € y el resto estará pendiente de ingreso (y lo mostraremos en el saldo al lado en color verde)

Si intentamos sacar más dinero del que hay en la cuenta se mostrará ‘Saldo insuficiente’.

Si sacamos dinero la cantidad se queda guardada y si queremos sacar más de 1000 € en una o varias operaciones nos saldrá un mensaje ‘Límite superado’

Tutoriales react y redux

Conceptos de Redux (puros)

https://code.tutsplus.com/es/tutorials/getting-started-with-redux-why-redux–cms-30349

Ejemplo de app de contactos (incompleta):

https://code.tutsplus.com/es/tutorials/getting-started-with-redux-learn-by-example–cms-30350

Un ejemplo extenso:

https://www.valentinog.com/blog/redux/

Otro tutorial sencillo:

https://daveceddia.com/redux-tutorial/

Página oficial:

https://react-redux.js.org/introduction/quick-start

Crear proyecto con React y Redux

npx create-react-app redux-counter

cd redux-counter

npm install –save redux react-redux

Creamos Counter.js:

import React from 'react';

class Counter extends React.Component {
  state = { count: 0 }

  increment = () => {
    this.setState({
      count: this.state.count + 1
    });
  }

  decrement = () => {
    this.setState({
      count: this.state.count - 1
    });
  }

  render() {
    return (
      <div>
        <h2>Counter</h2>
        <div>
          <button onClick={this.decrement}>-</button>
          <span>{this.state.count}</span>
          <button onClick={this.increment}>+</button>
        </div>
      </div>
    )
  }
}

export default Counter;

Después de modificarlo:

import React from 'react';
import { connect } from 'react-redux';

function mapStateToProps(state) {
  return {
    count: state.count
  };
}

    
class Counter extends React.Component {
  //state = { count: 0 }

  increment = () => {
   this.props.dispatch({ type: "INCREMENT" });
  }

  decrement = () => {
  this.props.dispatch({ type: "DECREMENT" });
  }

  render() {
    return (
      <div>
        <h2>Counter</h2>
        <div>
          <button onClick={this.decrement}>-</button>
          <span>{this.props.count}</span>
          <button onClick={this.increment}>+</button>
        </div>
      </div>
    )
  }
}

export default connect(mapStateToProps)(Counter);

App

import React from 'react';
import logo from './logo.svg';
import './App.css';
import Counter from './Counter';
import { createStore } from 'redux';
import { Provider } from 'react-redux';

const initialState = {
  count: 0
};
function reducer(state = initialState, action) {
  console.log('reducer', state, action);
  switch (action.type) {
    case 'INCREMENT':
      return {
        count: state.count + 1
      };
    case 'DECREMENT':
      return {
        count: state.count - 1
      };
    case 'RESET':
      return {
        count: 0
      };
    default:
      return state;
  }
}
const store = createStore(reducer);

function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
}

export default App;

Enrutamiento

Instalar:

npm install react-router-dom

https://reacttraining.com/react-router/web/example/basic
https://learnwithparam.com/blog/basic-routing-in-react-router/
https://medium.com/@simonhoyos/enrutando-en-react-cd9e4ad6e3d3

Ejemplo:

import React from "react";
import {
BrowserRouter as Router,
        Switch,
        Route,
        Link,
        useParams,
        Redirect
        } from "react-router-dom";

export default function App() {
    return (
            <Router>
                <div>
                    <nav>
                        <ul>
                            <li>
                                <Link to="/">Home</Link>
                            </li>
                            <li>
                                <Link to="/about">About</Link>
                            </li>
                               <li>
                                <Link to="/acerca">Acerca</Link>
                            </li>
                            <li>
                                <Link to="/users">Users</Link>
                            </li>
                            <li>
                                <Link to="/usuario/1">us1</Link>
                            </li>
                            <li>
                                <Link to="/usuario/2">us2</Link>
                            </li>
                        </ul>
                    </nav>
            
            
                    <Switch>
                    <Route path="/usuario/:id"  component={Usuario} />
                       
                    <Route exact path="/about">
                        <About />
                    </Route>
                    <Route exact path="/acerca">
                        <Acerca />
                    </Route>
                    <Route path="/users" component={Users}/>
                    <Route exact path="/">
                        <Home />
                    </Route>
            
                    </Switch>
                </div>
            </Router>
            );
}

function Home() {
    return <h2>Home</h2>;
}

function About() {
    return <h2>About</h2>;
}
function Acerca() {
    return <Redirect to='/about' />;
}
function Users() {
    return <h2>Users</h2>;
}

function Usuario() {
    
    let {id} = useParams();

    return (
            <div>
                <h3>ID: {id}</h3>
            </div>
            );
}

JSX React

Fragmentos:

// Example 1: Using empty tags <></> 
  render() {
    return ( 
      <>
        <ComponentA />
        <ComponentB />
        <ComponentC />
      </>
    );
  }

// Example 2: Using React.Fragment 
  render() {
    return ( 
      <React.Fragment>
        <h1>An h1 heading</h1> 
        Some text here. 
        <h2>An h2 heading</h2> 
        More text here.
        Even more text here.
       </React.Fragment>
    ); 
  }

  // Example 3: Importing the Fragment
  import React, { Fragment } from 'react';

  render() {
    return ( 
      <Fragment>
        <h1>An h1 heading</h1> 
        Some text here. 
        <h2>An h2 heading</h2> 
        More text here.
        Even more text here.
      </Fragment>
    ); 
  }

  return [
      <li key="1">First item</li>, 
      <li key="2">Second item</li>, 
      <li key="3">Third item</li>
    ]; 
  }

Espacios:

 <div> 
    <span>My</span> 
    {' '}
    name is
    {' '} 
    <span>Carlos</span> 
  </div>

Spread atributes:

  const attrs = { 
    id: 'myId',
    className: 'myClass'
  };
   
  return <div {...attrs} />;

Esto nos sirve para pasar un estado como propiedades a otro componente:

class MyApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'CamperBot',
      price:0
    }
  }
  render() {
    return (
       <div>
         <Navbar {...this.state} />
       </div>
    );
  }
};

class Navbar extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
    <div>
      <h1>Hello, my name is: {this.props.name} {this.props.price} </h1>
    </div>
    );
  }
};

Condicionales:

<div> 
    {isLoggedIn && <LoginButton />} 
  </div>

  <div> 
    {isLoggedIn ? <LogoutButton /> : <LoginButton />} 
  </div>

Propiedades por defecto:

class Button extends React.Component { 
    render() { 
      return <button>{this.props.text}</button>;
    } 
  } 
   
  Button.propTypes = { 
    text: React.PropTypes.string
  };
   
  Button.defaultProps = { 
    text: 'Click me!'
  };

Tres maneras de hacer el binding de las funciones:

 class Button extends React.Component { 
    constructor(props) { 
      super(props);
   
      this.handleClick = this.handleClick.bind(this);
    } 
   
    handleClick() { 
      console.log(this);
    } 
   
    render() { 
      return <button onClick={this.handleClick} />;
    } 
  }

  class Button extends React.Component { 
    handleClick() { 
      console.log(this);
    } 
   
    render() { 
      return <button onClick={() => this.handleClick()} />;
    } 
  }

class Button extends React.Component {    
    handleClick = () => { 
      console.log(this);
    } 
   
    render() { 
      return <button onClick={this.handleClick} />;
    } 
  }

Cambiar estado:

// Incorrecto
this.setState({
  counter: this.state.counter + this.props.increment,
});

// Correcto
this.setState((state, props) => ({
  counter: state.counter + props.increment
}));

Ejercicio (I)

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class Boton extends Component {
    mas = () => {
        this.props.mas(0);
    }
    render() {

        return (
            <button onClick={this.mas}>+</button>
        );
    }
}
;
class Fila extends Component {

    menos = () => {
        this.props.menos(this.props.indice);
    }
    render() {
        return (
            <p><input type="number" value={this.props.valor}></input>
                <button onClick={this.menos}>-</button>
            </p>
        );
    }
}
class Total extends Component {
    render() {
        return (
            <p>Total:{this.props.suma}</p>
        )
    }
}
class Tabla extends Component {
    constructor(props) {
        super(props);
        this.state = {
            numeros: [1, 2, 90, 0, 45]
        };

    }
    mas = (valor) => {
        this.setState({ numeros: [...this.state.numeros, valor] });
    }
    menos = (index) => {
        this.setState({
            numeros: this.state.numeros.filter((numero, i) => i != index)
        });
    }
    render() {
        const filas = this.state.numeros.map((valor, index) => {
            return (<Fila key={index} indice={index} valor={valor} menos={this.menos} />);
        });
        const suma = this.state.numeros.reduce((a, b) => a + b, 0);
        return (
            <div>
                <Boton mas={this.mas} />
                {filas}
                <Total suma={suma} />
            </div>
        );
    }
}
;
class App extends Component {
    render() {
        return (
            <Tabla />
        );
    }
}



;
export default App;