Giter Club home page Giter Club logo

curso-react-testing-graphql's Introduction

curso-react-testing-graphql's People

Contributors

next-sergiozamarro avatar zamarrowski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

curso-react-testing-graphql's Issues

Actualizando state no inmediato

Hola!

Estaba trabajando con el LocalStorage, y en una función de añadir item actualizo el state:

            this.setState({cart: [...this.state.cart,{id:addProduct.id,units:1}]})
            console.log(this.state.cart)

Pero curiosamente cuando imprimo a continuación el valor de state me devuelve el estado anterior, la solución parece ser esta:

            let newCart = [...this.state.cart,{id:addProduct.id,units:1}]
            this.setState({cart: newCart})
            console.log(newCart)

Me gustaría saber a que se debe, gracias!

Test

import { changeOrderByPrice, getPriceColor } from './Functions'

test('order ascending', () => {
    const productsOreder = [
        {
            id: 1,
            name: 'Chachopo',
            price: 30,
        },
        {
            id: 3,
            name: 'Navajas',
            price: 25,
        },
        {
            id: 2,
            name: 'Chorizo a la sidra',
            price: 15,
        }
    ]
    const products = [

        {
            id: 3,
            name: 'Navajas',
            price: 25,
        },
        {
            id: 1,
            name: 'Chachopo',
            price: 30,
        },
        {
            id: 2,
            name: 'Chorizo a la sidra',
            price: 15,
        }
    ]
    expect(changeOrderByPrice(products)).toStrictEqual(productsOreder);
    expect(changeOrderByPrice()).toBe(null);
})

test('color red', () => {
    expect(getPriceColor(30)).toBe('red');
})

test('color orange', () => {
    expect(getPriceColor(25)).toBe('orange');
})

test('color green', () => {
    expect(getPriceColor()).toBe('green');
    expect(getPriceColor(undefined)).toBe('green');
    expect(getPriceColor(null)).toBe('green');
    expect(getPriceColor(15)).toBe('green');
})

Select

import React from 'react';
import logo from './logo.svg';
import './App.css';
import Select from './Select';

const languages = [
  {
    value: 'es',
    text: 'español'
  },
  {
    value: 'en',
    text: 'english'
  }
]

const countries = [
  {
    value: 'es',
    text: 'spain'
  },
  {
    value: 'usa',
    text: 'usa'
  }
]

class App extends React.Component {

  state = {
    selectedLanguage: 'es',
    selectedCountry: 'es',
  }
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <Select 
            items={languages} 
            value={this.state.selectedLanguage} 
            onChange={(e) => this.setState({ selectedLanguage: e.target.value })}
          />

          <Select 
            items={countries} 
            value={this.state.selectedCountry} 
            onChange={(e) => this.setState({ selectedCountry: e.target.value })}
          />
        </header>
      </div>
    );
  }
}

export default App;

Ejercicio password

import React from 'react'
import CheckPassword from './CheckPassword'

class LoginForm extends React.Component {
  state = {
    password: ''
  }

  handleChange = e => {
    this.setState({
      password: e.target.value
    })
  }

  render() {
    return (
      <>
        <input type="text" value={this.state.password} onChange={this.handleChange} />
        <CheckPassword password={this.state.password} />
      </>
    )
  }
}

export default LoginForm
import React from 'react'

export default props => {

  let texto = ''
  let points = 0

  if (!props.password) {
    texto = 'no hay contraseña'
  }

  if (props.password.length >= 8) points++
  if (/[0-9]/.test(props.password)) points++
  if (/[A-Z]/.test(props.password)) points++
  if (/[$%&/()+-]/.test(props.password)) points++

  if (points === 0 && props.password) texto = 'contraseña muy debil'
  if (points === 1) texto = 'contraseña débil'
  if (points > 1 && points <= 3) texto = 'contraseña media'
  if (points >= 4) texto = 'contraseña fuerte'

  return (
    <p>{texto}</p>
  )
}

Clase 4

FormTest.js

import React from 'react'
import InputError from './InputError'

export default class FormTest extends React.Component {

  render() {
    return (
      <>
        <InputError />
      </>
    )
  }
}

helpers.js

export const sum = (num1, num2) => num1 + num2

InputError.js

import React from 'react'

const validText = 'A tope con React'

export default class InputError extends React.Component {

  state = {
    text: ''
  }

  render() {
    return(
      <>
        <input
          type="text"
          value={this.state.text}
          onChange={e => this.setState({ text: e.target.value })}
        />
        {this.state.text !== validText && <p style={{color: 'red'}}>El texto introducido no mola</p>}
      </>
    )
  }
}

Login.js

import React from 'react'

export default class Login extends React.Component {

  state = {
    username: '',
    password: '',
  }

  handleChange = e => {
    this.setState({
      [e.target.name]: e.target.value
    })
  }

  checkForm = () => {
    return this.state.username && this.state.password.length >= 8
  }

  onSubmitForm = e => {
    console.log(this.state)
    e.preventDefault()
  }

  render() {
    return (
      <form onSubmit={this.onSubmitForm} onChange={this.handleChange}>
        <input name="username" type="text" />
        <input name="password" type="password" />
        <button disabled={!this.checkForm()} type="submit">Login</button>
      </form>
    )
  }

}

Select.js

import React from 'react'

export default props =>
  <select value={props.value} onChange={props.onChange}>
    {props.items.map(val => (
      <option value={val}>{val}</option>
    ))}
  </select>

select.test.js

import { sum } from './helpers'

test('Should return 4', () => {
  expect(sum(2, 2)).toBe(4)
})

Opiniones

Bueno, aquí debajo puedes ver opiniones de las personas que han hecho el curso conmigo. Seguro que habrá alguna mala pero espero que la mayoría sean buenas ❤️

Espero que esto me ayude a mejorar y también para que las demás personas se hagan una idea de cómo es el curso :)

Ejercicio 1 Componentes y propiedades

App.js

<Title text="Necesito partir en componentes todo esto" />
        <Text>Para ello puedo usar React que me permitirá poder reutilizar todos esos componentes. Para ello tengo que:</Text>
        <List>
          <ListItem>Observar el HTML</ListItem>
          <ListItem>Pensar en como puedo extraer cada trozo en componentes</ListItem>
          <ListItem>Usarlos en React</ListItem>
        </List>
        <Link to="https://reactjs.org/" text="React Docs" />

Title.js

import React from 'react'

export default props => <h1>{props.text}</h1>

Text.js

import React from 'react'

export default props =>
  <p>{props.children}</p>

List.js

import React from 'react'

export default props =>
  <ul>
    {props.children}
  </ul>

ListItem.js

import React from 'react'

export default props => <li>{props.children}</li>

Link.js

import React from 'react'

export default props =>
  <a href={props.to} target={props.openInNewTab ? '_blank' : '_self'}>{props.text}</a>

Pensando en React ejercicio

App.js

import React from 'react'

import './App.css'
import productsConstants from './products.constants'
import ProductsList from './ProductsList'

class App extends React.Component {

  state = {
    selectedProducts: [],
    codeText: '',
    applyDiscount: false,
  }

  addProduct = product => {
    this.setState({ selectedProducts: [...this.state.selectedProducts, product] })
  }

  removeProduct = product => {
    this.setState({ selectedProducts: this.state.selectedProducts.filter(p => p.id !== product.id) })
  }

  getTotalPrice = () => {
    let totalPrice = this.state.selectedProducts.reduce((prev, next) => prev + next.price, 0)
    if (this.state.applyDiscount) totalPrice *= 0.90
    return totalPrice
  }

  applyDiscount = () => {
    if (this.state.codeText === 'SAVE10') {
      this.setState({ applyDiscount: true })
    } else {
      alert('Invalid code')
    }
  }

  onHandleCode = e => {
    this.setState({ codeText: e.target.value })
  }

  componentDidUpdate() {
    localStorage.setItem('state', JSON.stringify(this.state))
  }

  componentDidMount() {
    this.setState(JSON.parse(localStorage.getItem('state')))
  }

  render() {
    return (
      <div>
        <div>
          <h1>Products</h1>
          <ProductsList products={productsConstants} onClick={this.addProduct} actionLabel="Add product" />
        </div>
        <div>
          <h1>Selected products</h1>
          <ProductsList products={this.state.selectedProducts} onClick={this.removeProduct} actionLabel="Remove product" />
          <p>Total price: {this.getTotalPrice()}</p>
          <input type="text" placeholder="Type code" onChange={this.onHandleCode} />
          <button onClick={this.applyDiscount}>Apply discount</button>
        </div>
      </div>
    )
  }

}

export default App

ProductsList.js

import React from 'react'

const ProductsList = props =>
  props.products.map(product => (
    <div key={product.id}>
      <div>Name: {product.name}</div>
      <div>Price: {product.price}</div>
      <img width="100" src={product.img} alt="" />
      <button onClick={() => props.onClick(product)}>{props.actionLabel}</button>
    </div>
  ))


export default ProductsList

products.constants.js

export default [
  {
    id: 1,
    name: 'iPhone 11',
    price: 700,
    img: 'https://thumb.pccomponentes.com/w-530-530/articles/23/233093/n1.jpg'
  },
  {
    id: 2,
    name: 'iPhone 12',
    price: 800,
    img: 'https://thumb.pccomponentes.com/w-530-530/articles/23/233099/b1.jpg'
  },
  {
    id: 3,
    name: 'iPhone 12S',
    price: 1000,
    img: 'https://thumb.pccomponentes.com/w-530-530/articles/17/170988/iphone-xs-gold-58-2-g97c-uw.jpg'
  }
]

Form

helpers.js

export const getHobbies = (hobby, checked, hobbies) => {
  if (checked) {
    return [...hobbies, hobby]
  } else {
    return hobbies.filter(h => h !== hobby)
  }
}

Form.js

import React from 'react'
import { getHobbies } from './helpers'

export default class Form extends React.Component {

  state = {
    name: '',
    firstName: '',
    description: '',
    gender: '',
    age: 0,
    country: '',
    province: '',
    hobbies: []
  }

  handleChange = (e) => {
    let name = e.target.name
    let value = e.target.value

    if (e.target.type === 'checkbox') {
      value = getHobbies(e.target.value, e.target.checked, this.state.hobbies)
    }

    this.setState({
      [name]: value
    })

  }

  handleSubmit = e => {
    console.log(this.state)
    e.preventDefault()
  }

  render() {
    return (
      <form onChange={this.handleChange} onSubmit={this.handleSubmit}>
        <input type="text" name="name" />
        <input type="text" name="firstName" />
        <textarea name="description" />
        <input type="radio" name="gender" value="male" /> Male
        <input type="radio" name="gender" value="female" /> Female
        <input type="number" name="age" />
        <select name="country">
          <option>Select one</option>
          <option value="spain">Spain</option>
          <option value="usa">USA</option>
        </select>
        {this.state.country === 'spain' && (
          <select name="province">
            <option>Select one</option>
            <option value="guadalajara">Guadalajara</option>
            <option value="madrid">Madrid</option>
          </select>
        )}
        <label>
          <input name="hobbies" type="checkbox" value="Games" />
          Games
        </label>
        <label>
          <input name="hobbies" type="checkbox" value="Football" />
          Football
        </label>
        <label>
          <input name="hobbies" type="checkbox" value="Basketball" />
          Basketball
        </label>
        <label>
          <input name="hobbies" type="checkbox" value="Art" />
          Art
        </label>
        <button type="submit">Enviar</button>
      </form>
    )
  }

}

helpers.test.js

const { getHobbies } = require("./helpers")

test('Should remove football from array', () => {
  expect(getHobbies('football', false, ['football']).length).toBe(0)
  expect(getHobbies('football', false, ['football'])).not.toContain('football')
})

test('Should add football from array', () => {
  expect(getHobbies('football', true, ['basketball']).length).toBe(2)
  expect(getHobbies('football', true, ['basketball'])).toContain('football')
  expect(getHobbies('football', true, ['basketball'])).toContain('basketball')
})

Carrito de la compra

app.js

import React from 'react'
import './App.css'
import Product from './Product'

class App extends React.Component {

  state = {
    selectedProducts: [],
    promoText: '',
    applyDiscount: false,
  }

  products = [
    {
      descriptionImg: 'iphone x',
      img: 'https://store.storeimages.cdn-apple.com/4668/as-images.apple.com/is/refurb-iphoneX-spacegray_AV2?wid=1144&hei=1144&fmt=jpeg&qlt=80&op_usm=0.5,0.5&.v=1548459944179',
      name: 'iPhone X',
      price: 1000
    },
    {
      descriptionImg: 'iphone 8',
      img: 'https://store.storeimages.cdn-apple.com/4668/as-images.apple.com/is/refurb-iphone8-gold?wid=1144&hei=1144&fmt=jpeg&qlt=80&op_usm=0.5,0.5&.v=1542226468997',
      name: 'iPhone 8',
      price: 800
    },
    {
      descriptionImg: 'iphone 7',
      img: 'https://images-na.ssl-images-amazon.com/images/I/618wAPmPJPL._AC_SL1000_.jpg',
      name: 'iPhone 7',
      price: 700
    }
  ]

  componentDidMount() {
    if (localStorage.products) {
      this.setState({
        selectedProducts: JSON.parse(localStorage.products)
      })
    }
  }

  addProduct = product => {
    this.setState({
      selectedProducts: [...this.state.selectedProducts, {...product, id: Math.random()}]
    }, () => {
      localStorage.products = JSON.stringify(this.state.selectedProducts)
    })
  }

  removeProduct = product => {
    this.setState({
      selectedProducts: this.state.selectedProducts.filter(p => p.id !== product.id)
    }, () => {
      localStorage.products = JSON.stringify(this.state.selectedProducts)
    })
  }

  getTotalPrice = () => {
    let total = this.state.selectedProducts.reduce((prev, next) => prev + next.price, 0)
    if (this.state.applyDiscount) return total * 0.9
    return total
  }

  handleChange = e => {
    this.setState({
      promoText: e.target.value
    })
  }

  applyDiscount = () => {
    if (this.state.promoText === 'SAVE10') {
      this.setState({
        applyDiscount: true
      })
    } else {
      alert('Código incorrecto')
    }
  }

  render() {
    return (
      <div className="app-container">
        <div>
          <h1>Products</h1>
          <div className="products-container">
            {this.products.map(product => (
              <Product
                key={product.name}
                descriptionImg={product.descriptionImg}
                img={product.img}
                name={product.name}
                price={product.price}
                onAddProduct={() => this.addProduct(product)}
              />
            ))}
          </div>
        </div>
        <div className="cart-container">
          <h1>Cart</h1>
          {this.state.selectedProducts.length === 0 && <p>No products added</p>}
          <div className="products-container">
            {this.state.selectedProducts.map(product => (
              <Product
                key={product.name}
                descriptionImg={product.descriptionImg}
                img={product.img}
                name={product.name}
                price={product.price}
                onRemoveProduct={() => this.removeProduct(product)}
              />
            ))}
          </div>
          <p>Total price: {this.getTotalPrice()}€</p>
          <input placeholder="PROMO CODE" type="text" onChange={this.handleChange} />
          <button onClick={this.applyDiscount}>Apply</button>
        </div>
      </div>
    )
  }
}

export default App

Product.js

import React from 'react'

export default props =>
  <div>
    <img alt={props.descriptionImg} src={props.img} height="150px" />
    <p>{props.name}</p>
    <p>{props.price}€</p>
    {props.onAddProduct && (
      <button onClick={props.onAddProduct}>Añadir</button>
    )}
    {props.onRemoveProduct && (
      <button onClick={props.onRemoveProduct}>Borrar</button>
    )}
  </div>

Shop

import React from 'react'
import './../App.css'
import ProductList from './ProductList'
import products from './products.constants'

class Shop extends React.Component {

  state = {
    selectedProducts: [],
    discountCode: '',
    applyDiscount: false,
  }

  componentDidMount() {
    if (localStorage.state) {
      this.setState(JSON.parse(localStorage.state))
    }
  }

  componentDidUpdate() {
    localStorage.state = JSON.stringify(this.state)
  }

  onAddProduct = product => {
    this.setState({ selectedProducts: [...this.state.selectedProducts, product] })
  }

  onRemoveProduct = product => {
    this.setState({ selectedProducts: this.state.selectedProducts.filter(p => p.id !== product.id) })
  }

  getTotalPrice = () => {
    const result = this.state.selectedProducts.reduce((acum, next) => acum + next.price, 0)
    return this.state.applyDiscount ? result * 0.90 : result
  }

  handleChangeDiscountCode = e => {
    this.setState({ discountCode: e.target.value })
  }

  onApplyDiscount = () => {
    this.setState({ applyDiscount: this.state.discountCode === 'SAVE10' })
  }

  render() {
    return (
      <>
        <h1>Shop</h1>
        <div className="shop-container">
          <div>
            Products:
            <ProductList 
              products={products} 
              action={(product) => <button onClick={() => this.onAddProduct(product)}>Add</button>} 
            />
          </div>
          <div>
            Selected Products:
            <ProductList 
              products={this.state.selectedProducts} 
              action={(product) => <button onClick={() => this.onRemoveProduct(product)}>Remove</button>} 
            />
            <h1>Total: {this.getTotalPrice()}</h1>
            <input value={this.state.discountCode} onChange={this.handleChangeDiscountCode} type="text" />
            <button onClick={this.onApplyDiscount}>Apply discount</button>
          </div>
        </div>
      </>
    )
  }

}

export default Shop
const ProductList = props => props.products.map(product => (
  <div key={product.id}>
    <img src={product.img} alt="iphone" height="100" />
    <p>Name: {product.name}</p>
    <p>Price: {product.price}</p>
    {props.action(product)}
  </div>
))


export default ProductList
const products = [
  {
    id: 1,
    name: 'iPhone X',
    price: 900,
    img: 'https://thumb.pccomponentes.com/w-300-300/articles/32/328890/1391-apple-iphone-12-pro-max-256gb-azul-pacifico-libre.jpg'
  },
  {
    id: 2,
    name: 'iPhone 12',
    price: 1200,
    img: 'https://thumb.pccomponentes.com/w-300-300/articles/32/328889/1312-apple-iphone-12-pro-max-256gb-oro-libre.jpg'
  },
  {
    id: 3,
    name: 'iPhone 13',
    price: 1500,
    img: 'https://thumb.pccomponentes.com/w-300-300/articles/32/328931/1319-apple-iphone-12-128gb-product-rojo-libre.jpg'
  },
]

export default products

Ejercicio TODO list

import React from 'react'

const List = props => 
    <ul>
        {props.children}
    </ul>

const ListItem = props => 
    <li>
        <InputText onChange={(e) => props.onChange(e, props.task.id)} value={props.task.text} /> 
        <BasicButton onClick={() => props.onDelete(props.task.text)} label="Borrar" />
    </li>

const InputText = props => 
    <input type="text" value={props.value} onChange={props.onChange} />

const Button = props => 
    <button onClick={props.onClick}>{props.label}</button>

const AddTaskButton = props => 
    <Button onClick={props.onClick} label={'Añadir boton'}/>

const BasicButton = props => 
    <button style={{backgroundColor: props.action ? 'green' : 'orange'}} onClick={props.onClick}>{props.label}</button>

export default class ListContainer extends React.Component {
    state = {
        tasks: [{
            id: 1,
            text: 'zamarro'
        }],
        text: '',
    }

    addTask = () => {
        this.setState({ tasks: [...this.state.tasks, this.state.text] })
    }

    deleteTask = (text) => {
        let newTasks = this.state.tasks.filter(el => el !== text)
        this.setState({ tasks: newTasks })
    }

    onChangeTask = (e, id) => {
        let tasks = this.state.tasks.map(element => {
            if (element.id === id) element.text = e.target.value
            return element
        })
        this.setState({ tasks: tasks })
    }

    render() {
        return(
            <>
                <List>
                    {this.state.tasks.map((element) => (
                        <ListItem 
                            onDelete={this.deleteTask}
                            onChange={this.onChangeTask}
                            task={element}
                            key={element}
                        />
                    ))}
                </List>
                <InpuText type="text" onChange={e => this.setState({ text: e.target.value })} />
                <BasicButton onClick={this.addTask} label="Añadir tarea" action="success"  />
            </>
        )
    }
}

Example refactor handle input changes

import React from 'react';
import logo from './logo.svg';
import './App.css';
import Test from './Test';

class App extends React.Component {

  state = {
    name: '',
    age: ''
  }

  toggleTestComponent = () => {
    this.setState({ status: !this.state.status })
  }

  handleChange = (e) => {
    this.setState({ [e.target.name]: e.target.value })
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <input type="text" name="name" value={this.state.name} onChange={this.handleChange}/>
          <input type="text" name="age" value={this.state.age} onChange={this.handleChange}/>
        </header>
      </div>
    );
  }
}

export default App;

Shop

import React from 'react'
import { getTotalPrice } from './clase3_3/helpers'
import Products from './clase3_3/Products'
import productsConstants from './clase3_3/products.constants'


class App extends React.Component {

  state = {
    products: [],
    code: '',
    applyDiscount: false,
  }

  componentDidMount() {
    if (localStorage.fictiziaShop) this.setState(JSON.parse(localStorage.fictiziaShop))
  }

  componentDidUpdate() {
    localStorage.fictiziaShop = JSON.stringify(this.state)
  }

  addProduct = product => {
    this.setState({ products: [...this.state.products, product] })
  }

  removeProduct = product => {
    this.setState({ products: this.state.products.filter(p => p.id !== product.id) })
  }

  handleChangeCode = e => {
    this.setState({ code: e.target.value })
  }

  applyDiscount = () => {
    if (this.state.code !== 'SAVE10') {
      alert('codigo erroneo')
    } else {
      this.setState({ applyDiscount: this.state.code === 'SAVE10' })
    }
  }

  render() {
    return (
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>
        <div>
          <h1>Products</h1>
          <Products
            products={productsConstants}
            onAddProduct={this.addProduct}
            button={(product) => <button onClick={() => this.addProduct(product)}>Add</button>}
          />
        </div>
        <div>
          <h1>Cart</h1>
          <Products
            products={this.state.products}
            onAddProduct={this.addProduct}
            button={(product) => <button onClick={() => this.removeProduct(product)}>Remove</button>}
          />
          <h3>Total: {getTotalPrice(this.state.products, this.state.applyDiscount)}</h3>
          <input onChange={this.handleChangeCode} type="text" placeholder="CODE" />
          <button onClick={this.applyDiscount}>Apply</button>
        </div>
      </div>
    )
  }

}

export default App
const Products = props => props.products.map(product => (
  <div key={product.id}>
    <img src={product.image} />
    <p>{product.name}</p>
    <p>{product.price}</p>
    {/* <button onClick={() => props.onAddProduct(product)}>Add</button> */}
    {props.button(product)}
  </div>
))

export default Products

Redux

store/configureStore.js

import { createStore } from 'redux'

import rootReducer from './reducers'

export default function configureStore() {
    return createStore(rootReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
}

store/reducers.js

import { combineReducers } from 'redux'

import form from './../form.reducer'

export default combineReducers({
    form
})

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { Provider } from 'react-redux'
import configureStore from './store/configureStore'
let store = configureStore()
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

form.actions.js

export const changeName = name => {
    return {
        type: 'CHANGE_NAME',
        name
    }
}

export const changeAge = age => {
    return {
        type: 'CHANGE_AGE',
        age
    }
}

form.reducer.js

const initialState = {
    name: '',
    age: 0
}

export default function(state=initialState, action) {
    switch (action.type) {
        case 'CHANGE_NAME':
            return { ...state, name: action.name }
        case 'CHANGE_AGE':
            return { ...state, age: action.age }
        default:
            return state
    }
}

app.js

import React from 'react';
import './App.css';
import { connect } from 'react-redux'
import * as formActions from './form.actions'
import UserInfo from './UserInfo';
function App(props) {
  return (
    <div className="App">
      <input type="text" 
        value={props.name} 
        onChange={e => props.changeName(e.target.value)} 
      />
      <input type="number"
        value={props.age}
        onChange={e => props.changeAge(e.target.value)} 
      />
      <UserInfo />
    </div>
  );
}

const mapStateToProps = state => {
  return {
    name: state.form.name,
    age: state.form.age,
  }
}

const mapDispatchToProps = dispatch => {
  return {
    changeName: name => dispatch(formActions.changeName(name)),
    changeAge: age => dispatch(formActions.changeAge(age)),
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App);

password strength

import React from 'react'

const PasswordStrength = props => {

  let texto = ''
  let points = 0

  if (!props.password) {
    texto = 'no hay contraseña'
  }

  if (props.password.length >= 8) points++
  if (/[0-9]/.test(props.password)) points++
  if (/[A-Z]/.test(props.password)) points++
  if (/[$%&/()+-]/.test(props.password)) points++

  if (points === 0 && props.password) texto = 'contraseña muy débil'
  if (points === 1) texto = 'contraseña débil'
  if (points > 1 && points <= 3) texto = 'contraseña media'
  if (points >= 4) texto = 'contraseña fuerte'

  return (
    <p>{texto}</p>
  )
}

export default PasswordStrength

Shop

import React, { Component } from 'react'

const products = [
	{
		id: 1,
		name: "Product1",
		price: 200
	},
	{
		id: 2,
		name: "Product2",
		price: 500
	},{
		id: 3,
		name: "Product3",
		price: 1200
	}
];

export default class Shop extends Component {

	state = {
		selectedProducts: [],
		couponName: '',
		isCouponValid: false
	}

	componentDidMount() {
		let selectedProducts = JSON.parse(localStorage.selectedProducts || '[]');
		let isCouponValid = !!localStorage.isCouponValid;

		this.setState({selectedProducts, isCouponValid});
	}

	render() {
		return (
			<div>
				<div className="products">
					{products.map(product =>
						<div key={product.id} className="product">
							<div className="productName">{product.name}</div>
							<div className="productPrice">{product.price}</div>
							<button onClick={() => this.addProduct(product)}>Añadir</button>
						</div>
					)}
				</div>
				<hr/>
				<div className="cart">
					Cart <span>Total {this.totalPrice()}$</span>
					<ul className="cartProducts">
						{this.state.selectedProducts.map((product, key) =>
							<li key={key} className="product">
								<div className="productName">{product.name}</div>
								<div className="productPrice">{product.price}</div>
								<button onClick={() => this.removeProduct(product)}>Borrar</button>
							</li>
						)}
					</ul>
				</div>
				<div className="coupon">
					<input value={this.state.couponName}
						onChange={this.handleChange} type="text"/>
					<button onClick={this.verifyCoupon}>Aplicar</button>
				</div>
			</div>
		)
	}

	addProduct = (product) => {
		let productClone = [...this.state.selectedProducts, product];
		this.setState({selectedProducts: productClone}, () => console.log(this.state.selectedProducts));

		this.updateLocalstorage(productClone, "selectedProducts");
	}

	removeProduct = (product) => {
		let newProducts = this.state.selectedProducts.filter(p => p !== product);
		this.setState({selectedProducts: newProducts});
		this.updateLocalstorage(newProducts, "selectedProducts");
	}

	totalPrice = () => {
		let total = this.state.selectedProducts.reduce((acum, item) => acum + item.price, 0);
		if(this.state.isCouponValid){
			total *= 0.9;
		}
		return total;
	}

	handleChange = (e) =>{
		let couponValue = e.target.value;
		this.setState({couponName: couponValue});
	}

	verifyCoupon = () =>{
		if(this.state.couponName === "SAVE10"){
			this.setState({isCouponValid: true})
			this.updateLocalstorage(true, "isCouponValid");
		}else{
			alert("Cupón caducado, listillo")
		}
	}

	updateLocalstorage = (data, attr) => {
		localStorage[attr] = JSON.stringify(data);
	}
}

login

import React from 'react'


class App extends React.Component {

  state = {
    username: '',
    password: '',
  }

  handleChange = e => {
    this.setState({ [e.target.name]: e.target.value })
  }

  isValid = () => {
    return this.state.username && this.state.password && this.state.password.length >= 8
  }

  handleSubmit = (e) => {
    e.preventDefault()
    console.log(this.state)
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit} onChange={this.handleChange}>
        <input name="username" type="text" />
        <input name="password" type="password" />
        <button disabled={!this.isValid()}>Login</button>
      </form>
    )
  }

}

export default App

Clase 1

Greeting.js

import React from 'react'

const Greeting = props => <h1>{props.children}</h1>

export default Greeting

Link.js

import React from 'react'

export default props =>
  <a href={props.to} target={props.openInNewTab ? '_blank' : '_self'}>{props.text}</a>

List.js

import React from 'react'

export default props =>
  <ul>
    {props.children}
  </ul>

ListItem.js

import React from 'react'

export default props => <li>{props.children}</li>

Loading.js

export default props => props.show ? props.children : 'Loading...'

ShowName.js

import React from 'react'

const ShowName = props => <p>{props.user.name} - {props.age}</p>

export default ShowName

TestChildren.js

import React from 'react'

const TestChildren = props =>
  <>
    <div>hola1</div>
    <div>hola2</div>
  </>

export default TestChildren

Text.js

import React from 'react'

export default props =>
  <p>{props.children}</p>

Title.js

import React from 'react'

export default props => <h1>{props.text}</h1>

Change text

import React from 'react'

class App extends React.Component {

  state = {
    text: ''
  }

  changeText = (e) => this.setState({ text: e.target.value })

  render() {
    return <>
      <h1>{this.state.text}</h1>
      <input type="text" onChange={this.changeText} />
    </>
  }

}

export default App

React Router

App.js

import React from 'react'
import './App.css'
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from 'react-router-dom'
import HomePage from './clase9/HomePage'
import UsersPage from './clase9/UsersPage'
import NotFoundPage from './clase9/NotFoundPage'

const App = () => {
  return (
    <div>
      <Router>
        <nav>
          <ul>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/users">Users</Link></li>
          </ul>
        </nav>

        <Switch>
          <Route exact path="/">
            <HomePage />
          </Route>
          <Route path="/users">
            <UsersPage />
          </Route>
          <Route path="*">
            <NotFoundPage />
          </Route>
        </Switch>
      </Router>
    </div>
  )
}

export default App

NotFoundPage.js

import React from 'react'

export default () => <h1>Page not found</h1>

UsersPage.js

import React from 'react'
import { Link, Switch, Route } from 'react-router-dom'
import UserDetail from './UserDetail'

const users = [{id: 1, username: 'zamarro'}, { id: 2, username: 'Cristina' }]

export default () => (
  <>
    <Switch>
      <Route exact path="/users">
        <ul>
        {users.map(user => (
          <li key={user.id}>
            <Link to={`/users/${user.id}`}>{user.username}</Link>
          </li>
        ))}
      </ul>
      </Route>
      <Route path="/users/:id">
        <UserDetail />
      </Route>
    </Switch>
  </>
)

HomePage.js

import React from 'react'

export default () => <h1>¡Bienvenido!</h1>

UserDetail.js

import React from 'react'
import { useParams } from 'react-router-dom'

export default () => {

  const { id } = useParams()

  return (<h1>El user id es: {id}</h1>)

}

testing

export const editTodo = (todos, value, id) => {
  return todos.map(todo => {
    if (todo.id === id) todo.title = value
    return todo
  })
}
import { editTodo } from "./helpers"

test('Should edit a todo', () => {
  const todos = [{ id: 1, title: 'hola' }]
  const newMessage = 'editado!'
  const newTodos = editTodo(todos, newMessage, todos[0].id)
  expect(newTodos[0].title).toBe(newMessage)
})

React Lazy

import React, {useState,Suspense} from 'react';

const Counter = React.lazy(() => import('./Counter'))

function App() {
const [load, setLoad] = useState(false);

return (
    <div className="App">
        <header className="App-header">
            <button onClick={()=>setLoad(!load)}>Toggle</button>
            {load &&
                <Suspense fallback={<div>Loading...</div>}>
                    <Counter/>
                </Suspense>
            }
        </header>
    </div>
)

}
export default App;

Ejemplo de componente wrappeado

import Btn from './../Btn/Btn'
import styled from 'styled-components'

const MiBtn = styled(Btn)`

    ${props => props.primary && css`
        color: green;
    `}
`

export default props => {

    return(
        <MiBtn {...props} />
    )

}

RouterContent.jsx

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

import {
	Home,
	Users,
	UserDetail,
	NotFound,
} from './RouterComponents';

import Navbar from './Navbar';

export default function RouterContent() {
	return (
		<Router>
			<Navbar />
			<Switch>
				<Route exact path="/">
					<Home />
				</Route>
				<Route path="/users/:id">
					<UserDetail />
				</Route>
				<Route path="/users">
					<Users />
				</Route>
				<Route path="*">
					<NotFound />
				</Route>
			</Switch>
		</Router>
	)
}


Actualizando estado de hooks

Hola!

Estoy tratando de animar el desplazamiento horizontal de un elemento con scrollLeft hasta 100px cuando hago click en un boton.

He creado una referencia al elemento con
const contenedorPreguntas = useRef();
y referenciado el elemento
<div ref={contenedorPreguntas} >

He creado un estado para tener seguimiento de por donde va el scroll:
const [scrollX, setScrollX] = useState(0);

Y con un boton que ejecute el scroll
<button onClick={scrollH}>Mover</button>
Y la función

  const scrollH = (e) => {
      if(scrollX<100){
        contenedorPreguntas.current.scrollLeft += 1; 
        setScrollX(scrollX+1); 
        setTimeout(function(){ scrollH(); },100);
      }
  }

El scroll funciona pero no para nunca, ya que scrollX siempre está a 0, y setScrollX no hace cambiar el valor, únicamente la primera vez que pincha el usuario. Me gustaría entender el funcionamiento y cómo solucionarlo. Gracias!

Clase 2

Button.js

import React from 'react'

export default props =>
  <button onClick={props.onPress}>{props.label}</button>

Chronometer.js

import React from 'react'

export default class Chronometer extends React.Component {
  state = {
    count: 0
  }

  updateStateInterval = null

  componentDidMount() {
    console.log('holi!')
  }

  componentDidUpdate(prevProps, prevState) {
    console.log(prevProps, prevState)
  }

  startChrono = () => {
    setTimeout(() => {
      this.setState({count: this.state.count + 1})
    }, 1000)
    setInterval(() => {
      this.setState({count: this.state.count + 1})
    }, 2000)
  }

  componentWillUnmount() {
    console.log('me voy!')
    clearInterval(this.updateStateInterval)
  }

  render() {
    return (
      <>
        <h1>{this.state.count}</h1>
        <button onClick={this.startChrono}>Start</button>
      </>
    )
  }
}

Counter.js

import React, { Component } from 'react'
import Title from './Title'
import Button from './Button'

class Counter extends Component {

  state = {
    count: 0,
  }

  handleChange = action => {
    this.setState(prevState =>
      ({ count: action === 'increment' ? prevState.count + 1 : prevState.count - 1 })
    )
  }

  render() {
    return (
      <>
        <Title text={this.state.count} />
        <Button onPress={() => this.handleChange('increment')} label="Increment"/>
        <Button onPress={() => this.handleChange('decrement')} label="Decrement"/>
      </>
    )
  }
}

export default Counter

CounterText.js

import React, { Component } from 'react'

class CounterText extends Component {

  state = {
    text: '',
  }

  increment = () => {
    this.setState(prevState => ({ text: prevState.text + 'a' }))
  }

  decrement = () => {
    this.setState(prevState => ({ text: prevState.text.slice(1) }))
  }

  render() {
    return (
      <>
        <div>{this.state.text}</div>
        <button onClick={this.increment}>Increment</button>
        <button onClick={this.decrement}>Decrement</button>
      </>
    )
  }
}

export default CounterText

Input.js

import React from 'react'

export default () => <input type="text" onChange={e => console.log(e.target.value)} />

Likes.js

import React from 'react'

export default class Likes extends React.Component {
  state = {
    likes: 50,
    liked: false
  }

  handleChange = () => {
    this.setState(prevState => ({
      liked: !prevState.liked,
      likes: prevState.liked ? prevState.likes-- : prevState.likes++
    }))
  }

  render() {
    return (
      <>
        <h1>{this.state.likes}</h1>
        <button onClick={this.handleChange}>{this.state.liked ? 'Dislike' : 'Like'}</button>
      </>
    )
  }
}

LogProps.js

import React from 'react'

export default props => {
  console.log(props)
  return(
    <p>Mira las developers tools</p>
  )
}

Password.js

import React from 'react'

export default class Password extends React.Component {
  state = {
    show: false
  }

  togglePassword = () => {
    this.setState(prevState => ({ show: !prevState.show }))
  }

  render() {
    return (
      <>
        <input type={this.state.show ? 'text' : 'password'} />
        <button onClick={this.togglePassword}>Toggle</button>
      </>
    )
  }
}

Title.js

import React from 'react'

const Title = (props) => <h1>{props.text}</h1>
export default Title

funciones

<li><input type="text" value={props.item.val} onChange={(e) => props.onChange(e,props.item.id) } /><Boton label="borrar" onClick={() => props.eliminarItem(props.item.id)} /></li>
en onChange ¿cuando se añade la función con un arrow function y cuando no hace falta?

RouterComponent.js

import React from 'react'
import { Link, useParams } from 'react-router-dom'

export function Home() {
	return (
		<h1>Qué pasa</h1>
	)
}

export function Users() {
	return (
		<ul>
			<li>
				<Link to="/users/roberto">Roberto</Link>
			</li>
			<li>
				<Link to="/users/diana">Diana</Link>
			</li>
		</ul>
	)
}

export function UserDetail() {
	const {id} = useParams();
	return (
		<h2>
			Hola {id}
		</h2>
	)
}

export function NotFound() {
	return (
		<div>
			Ande vas?
		</div>
	)
}
```

Navbar.jsx

import React from 'react';
import { Link } from 'react-router-dom';

export default function Navbar() {
	return (
		<nav>
			<ul>
				<li>
					<Link to="/">Home</Link>
				</li>
				<li>
					<Link to="/users">Users</Link>
				</li>
			</ul>
		</nav>
	)
}

Context

`
/App.js/
import React, { useState } from 'react';
import AppContext from './AppContext';
import Header from './Header'
import Content from './Content'

function App() {
const [language, setLanguage] = useState('es')

return (



<AppContext.Provider value={{
language: language,
changeLanguage: (language) => setLanguage(language)
}}>


</AppContext.Provider>


);
}
export default App;

/AppContext.js/
import React from 'react';
export default React.createContext({language:'es', changeLanguage:()=>{}});

/Header.js/
import React, { useContext } from 'react'
import AppContext from './AppContext'

export default props => {
const context = useContext(AppContext)
return (


<button onClick={() => context.changeLanguage(context.language === 'es' ? 'en': 'es')}>
{context.language === 'es' ? 'Cambiar idioma' : 'Change language'}


)
}

/Content.js/
import React from 'react';
import ContentText from './ContentText'
import ContentButton from './ContentButton'

function Content(){
return(





)
}
export default Content;

/* ContentText.js*/
import React from 'react';
import AppContext from './AppContext'

class ContentText extends React.Component{
static contextType = AppContext;

render(){
    return(
        <p>
            {this.context.language==='es' ? "Hola" : "Hello"}
        </p>
    )
}

}
export default ContentText;

/* ContentButton.js*/
import React, {useContext} from 'react';
import AppContext from './AppContext';

function ContentButton(){
const context = useContext(AppContext);
return(

{context.language==='es' ? "Púlsame" : "Click me"}

)
}
export default ContentButton;
`

FetchTodos

import React, { useState, useEffect } from 'react'

export default () => {

  const [todos, setTodos] = useState([])

  const fetchTodos = async () => {
    let response = await fetch('https://jsonplaceholder.typicode.com/todos')
    let data = await response.json()
    setTodos(data)
  }

  useEffect(() => {
    fetchTodos()
  }, [])

  return (
    <>
      <h1>Todos</h1>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            {todo.title}
          </li>
        ))}
      </ul>
    </>
  )
}

chrono

import React from 'react'

class Chrono extends React.Component {

  state = {
    count: 0
  }

  countInterval = null

  componentWillUnmount() {
    this.stop()
  }

  start = () => {
    this.countInterval = setInterval(() => {
      this.setState(state => ({ count: state.count + 1 }))
      console.log('actualizado')
    }, 1000)
  }

  stop = () => clearInterval(this.countInterval)

  render() {
    return (
      <>
        <h1>{this.state.count}</h1>
        <button onClick={this.start}>Start</button>
        <button onClick={this.stop}>Stop</button>
      </>
    )
  }

}

export default Chrono

Server side rendering

¡Hola!
Me gustaría saber si vamos a aprender el Server side rendering para que nuestras aplicaciones sean cacheables por google :) ya que por defecto react carga todo el contenido dinámicamente, y el código fuente muestra solo el div root, gracias!

fetch todos

import React from 'react'

class Tasks extends React.Component {

  state = {
    tasks: []
  }

  componentDidMount() {
    this.fetchTasks()
  }

  fetchTasks = async () => {
    let response = await (await fetch('https://jsonplaceholder.typicode.com/todos')).json()
    this.setState({ tasks: response })
  }

  render() {
    return <pre>{JSON.stringify(this.state.tasks)}</pre>
  }

}

export default Tasks

Custom Hook

TodoList.js

import React, { useState, useEffect } from 'react'
import useApiCall from './useApiCall'

export default () => {

  const [todos, loading] = useApiCall('https://jsonplaceholder.typicode.com/todos')

  return (
    <>
      <h1>Todos</h1>
      <ul>
        {todos && todos.map(todo => (
          <li key={todo.id}>
            {todo.title}
          </li>
        ))}
      </ul>
    </>
  )
}

useApiCall.js

import { useState, useEffect } from 'react'

export default url => {

  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(false)

  const fetchData = async (url) => {
    setLoading(true)
    let response = await fetch(url)
    let data = await response.json()
    setData(data)
    setLoading(false)
  }

  useEffect(() => {
    fetchData(url)
  }, [url])

  return [data, loading]
}

Examples class 1

App.js:

import React from 'react';
import logo from './logo.svg';
import './App.css';
import Test from './Test';

class App extends React.Component {

  state = {
    status: false
  }

  toggleTestComponent = () => {
    this.setState({ status: !this.state.status })
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          {this.state.status ? <Test /> : ''}
          <button onClick={this.toggleTestComponent}>Mostrar/ocultar</button>
        </header>
      </div>
    );
  }
}

export default App;

Test.js:

import React, { Component } from 'react'

class Test extends Component {

    state = {
        users: ['sergio', 'zamarro']
    }

    componentDidMount() {
        let users = [...this.state.users]
        users.push('otro')
        this.setState({ users })
    }

    render() {
        return JSON.stringify(this.state.users)
    }

    componentWillUnmount() {
        console.log('Me destruyo!')
    }

}

export default Test

Carrito de la compra

ShopPage.js

import React from 'react'
import productsConstants from './products.constants'
import ProductsList from './ProductsList'
import { getPrice } from './helpers'

class ShopPage extends React.Component {

  state = {
    selectedProducts: [],
    discountCode: '',
    applyDiscount: false,
  }

  componentDidMount() {
    const selectedProducts = this.getProductsFormLocalStorage()
    this.setState({ selectedProducts })
  }

  addProduct = product => {
    const newProducts = [...this.state.selectedProducts, product]
    this.setProductsInLocalStorage(newProducts)
    this.setState({
      selectedProducts: newProducts
    })
  }

  removeProduct = product => {
    const newProducts = this.state.selectedProducts.filter(p => p.id !== product.id)
    this.setProductsInLocalStorage(newProducts)
    this.setState({
      selectedProducts: newProducts
    })
  }

  setProductsInLocalStorage = products => {
    localStorage.selectedProducts = JSON.stringify(products)
  }

  getProductsFormLocalStorage = () => {
    const selectProducts = localStorage.selectedProducts
    if (selectProducts) return JSON.parse(localStorage.selectedProducts)
    return []
  }

  handleChangeDiscountCode = e => {
    this.setState({
      discountCode: e.target.value
    })
  }

  validateDiscountCode = () => {
    if (this.state.discountCode === 'SAVE10') {
      this.setState({ applyDiscount: true })
    } else {
      this.setState({ applyDiscount: false })
    }
  }

  render() {
    return (
      <div className="shopContainer">
        <div>
          <h1>Products</h1>
          <ProductsList products={productsConstants} button={product => <button onClick={() => this.addProduct(product)}>Add product</button>} />
        </div>
        <div>
          <h1>Selected Products</h1>
          <ProductsList products={this.state.selectedProducts} button={product => <button onClick={() => this.removeProduct(product)}>Remove product</button>} />
          <input type="text" onChange={this.handleChangeDiscountCode}/>
          <button onClick={this.validateDiscountCode}>Validate discount code</button>
          {this.state.selectedProducts.length > 0 && <p>Total: {this.state.applyDiscount ? getPrice(this.state.selectedProducts) * 0.90 : getPrice(this.state.selectedProducts)}</p>}
        </div>
      </div>
    )
  }

}

export default ShopPage

ProductList.js

import React from 'react'

export default props => {
  return (
    props.products.map(product => (
      <div key={product.id}>
        {product.name} - {product.price}
        {props.button(product)}
      </div>
    ))
  )
}

Chronometer.js

import React from 'react'

class Chronometer extends React.Component {

  state = {
    count: 0
  }

  startChronometer = () => {
    setInterval(() => {
      this.setState(prevState => ({ count: prevState.count + 1 }))
    }, 1000)
  }

  render() {
    return (
      <>
        <h1>{this.state.count}</h1>
        <button onClick={this.startChronometer}>Start</button>
      </>
    )
  }

}

export default Chronometer

hooks part 5

`import React, { useState, useEffect } from 'react';

const Form = () => {
const [ nombre, setNombre ] = useState('')
const [ showError, setShowError ] = useState(false)

useEffect(() => {
    if (nombre == 'zamarro') {
        setShowError(true) 
    } else {
    setShowError (false) 
    }
}, [nombre])

return (        
    <form>            
    <input
        type="text"
        value={nombre}
        onChange={e => setNombre(e.target.value)}
        />
        { !showError && <span>error</span> } 
    </form>   
);

};
export default Form;`

Clase 3

AddTaskButton.js

import React from 'react'

export default props => <button onClick={props.onAdd}>Add task</button>

InputText.js

import React from 'react'

export default props => <input type="text" value={props.value} onChange={props.onChange} />

List.js

import React from 'react'
import ListItem from './ListItem'

export default props =>
  <ul>
    {props.tasks.map(task => (
      <ListItem
        key={task.id}
        task={task}
        onRemove={props.onRemove}
        onEdit={props.onEdit}
      />
    ))}
  </ul>

ListContainer.js

import React from 'react'
import List from './List'
import InputText from './InputText'
import AddTaskButton from './AddTaskButton'

class ListContainer extends React.Component {

  state = {
    tasks: [{
      id: 10001,
      title: 'Comprar el pan'
    }, {
      id: 10002,
      title: 'Sacar a India'
    }],
    newTaskText: ''
  }

  handleNewTaskText = e => {
    this.setState({ newTaskText: e.target.value })
  }

  addTask = () => {
    this.setState({
      tasks: [...this.state.tasks, { id: Math.random(), title: this.state.newTaskText }],
      newTaskText: '',
    })
  }

  removeTask = taskId => {
    let newTasks = this.state.tasks.filter(task => task.id !== taskId)
    this.setState({ tasks: newTasks })
  }

  editTask = (taskId, value) => {
    const newTasks = this.state.tasks.map(task => {
      if (task.id === taskId) task.title = value
      return task
    })
    this.setState({ tasks: newTasks })
  }

  render() {
    return (
      <>
        <List tasks={this.state.tasks} onRemove={this.removeTask} onEdit={this.editTask} />
        <InputText onChange={this.handleNewTaskText} value={this.state.newTaskText} />
        <AddTaskButton onAdd={this.addTask} />
      </>
    )
  }

}

export default ListContainer

ListItem.js

import React from 'react'
import RemoveTaskButton from './RemoveTaskButton'

export default props =>
  <>
    <li>
      <input
        type="text"
        value={props.task.title}
        onChange={e => props.onEdit(props.task.id, e.target.value)}
      />
    </li>
    <RemoveTaskButton onRemove={() => props.onRemove(props.task.id)} />
  </>

RemoveTaskButton.js

import React from 'react'

export default props => <button onClick={props.onRemove}>Remove</button>

Seconds.js

import React from 'react'

export default class Seconds extends React.Component {
  state = {
    count: 0
  }

  componentDidMount() {
    setInterval(() => {
      this.setState(prevState => ({count: prevState.count++}))
    }, 1000)
  }

  render() {
    return (
      <>
        <h1>{this.state.count}</h1>
      </>
    )
  }
}

Tasks.js

import React from 'react'

export default class Tasks extends React.Component {
  state = {
    tasks: []
  }

  fetchTasks = async () => {
    let data = await (await fetch('https://jsonplaceholder.typicode.com/todos')).json()
    this.setState({ tasks: data })
  }

  componentDidMount() {
    this.fetchTasks()
  }

  render() {
    return <pre>{JSON.stringify(this.state.tasks)}</pre>
  }
}

Test.js

import React from 'react'

class Test extends React.Component {

  state = {
    text: 'hola',
  }

  componentDidMount() {
    console.log('despues del primer render')
  }

  componentDidUpdate() {
    console.log('se ha actualizado')
  }

  componentWillUnmount() {
    console.log('adiós')
  }

  render() {
    return (
      <>
        <h1>{this.state.text}</h1>
        <input type="text" onChange={e => this.setState({ text: e.target.value })} />
      </>
    )
  }

}

export default Test

Users.js

import React from 'react'

export default class Users extends React.Component {
  state = {
    users: ['sergio', 'vero']
  }

  componentDidMount() {
    this.setState(prevState => ({ users: [...prevState.users, 'cris'] }))
  }

  render() {
    return <p>{this.state.users.join(', ')}</p>
  }

  componentWillUnmount() {
    console.log('¡Componente destruido!')
  }
}

Clase 5

Child.js

import React from 'react'

export default class Child extends React.Component {
  state = {
    text: 'hola desde el hijo'
  }

  pepino = () => {
    this.props.holi(this.state.text)
  }

  render() {
    return (
      <>
        <h1>{this.state.text}</h1>
        <button onClick={this.pepino}>holi</button>
      </>
    )
  }

}

Form.js

import React from 'react'
import { getHobbies } from './helpers'
import Child from './Child'

export default class Form extends React.Component {

  state = {
    name: '',
    firstName: '',
    description: '',
    gender: '',
    age: 0,
    country: '',
    province: '',
    hobbies: []
  }

  handleChange = (e) => {
    let name = e.target.name
    let value = e.target.value

    if (e.target.type === 'checkbox') {
      value = getHobbies(e.target.value, e.target.checked, this.state.hobbies)
    }

    this.setState({
      [name]: value
    })

  }

  handleSubmit = e => {
    console.log(this.state)
    e.preventDefault()
  }

  holi = data => {
    console.log(data)
  }

  render() {
    return (
      <form onChange={this.handleChange} onSubmit={this.handleSubmit}>
        <input type="text" name="name" />
        <input type="text" name="firstName" />
        <textarea name="description" />
        <input type="radio" name="gender" value="male" /> Male
        <input type="radio" name="gender" value="female" /> Female
        <input type="number" name="age" />
        <select name="country">
          <option>Select one</option>
          <option value="spain">Spain</option>
          <option value="usa">USA</option>
        </select>
        {this.state.country === 'spain' && (
          <select name="province">
            <option>Select one</option>
            <option value="guadalajara">Guadalajara</option>
            <option value="madrid">Madrid</option>
          </select>
        )}
        <label>
          <input name="hobbies" type="checkbox" value="Games" />
          Games
        </label>
        <label>
          <input name="hobbies" type="checkbox" value="Football" />
          Football
        </label>
        <label>
          <input name="hobbies" type="checkbox" value="Basketball" />
          Basketball
        </label>
        <label>
          <input name="hobbies" type="checkbox" value="Art" />
          Art
        </label>
        <Child holi={this.holi} />
        <button type="submit">Enviar</button>
      </form>
    )
  }

}

helpers.js

export const getHobbies = (hobby, checked, hobbies) => {
  if (checked) {
    return [...hobbies, hobby]
  } else {
    return hobbies.filter(h => h !== hobby)
  }
}

//[{price: 500}, {price: 250}]
export const getPrice = products => {
  return products.reduce((prev, current) => prev + current.price, 0)
}

helpers.test.js

const { getHobbies, getPrice } = require("./helpers")

test('Should remove football from array', () => {
  expect(getHobbies('football', false, ['football']).length).toBe(0)
  expect(getHobbies('football', false, ['football'])).not.toContain('football')
})

test('Should add football from array', () => {
  expect(getHobbies('football', true, ['basketball']).length).toBe(2)
  expect(getHobbies('football', true, ['basketball'])).toContain('football')
  expect(getHobbies('football', true, ['basketball'])).toContain('basketball')
})

test('Should return 0 if products is an empty array', () => {
  expect(getPrice([])).toBe(0)
})

test('Should return 500', () => {
  const products = [{ price: 250 }, { price: 250 }]
  expect(getPrice(products)).toBe(500)
})

TODO tasks

ListContainer.js

import React from 'react'
import List from './List'
import InputText from './InputText'
import AddTaskButton from './AddTaskButton'

class ListContainer extends React.Component {

  state = {
    tasks: [{
      id: 10001,
      title: 'Comprar el pan'
    }, {
      id: 10002,
      title: 'Sacar a India'
    }],
    newTaskText: ''
  }

  handleNewTaskText = e => {
    this.setState({ newTaskText: e.target.value })
  }

  addTask = () => {
    this.setState({
      tasks: [...this.state.tasks, { id: Math.random(), title: this.state.newTaskText }],
      newTaskText: '',
    })
  }

  removeTask = taskId => {
    let newTasks = this.state.tasks.filter(task => task.id !== taskId)
    this.setState({ tasks: newTasks })
  }

  render() {
    return (
      <>
        <List tasks={this.state.tasks} onRemove={this.removeTask} />
        <InputText onChange={this.handleNewTaskText} value={this.state.newTaskText} />
        <AddTaskButton onAdd={this.addTask} />
      </>
    )
  }

}

export default ListContainer

List.js

import React from 'react'
import ListItem from './ListItem'

export default props =>
  <ul>
    {props.tasks.map(task => (
      <ListItem key={task.id} title={task.title} onRemove={() => props.onRemove(task.id)} />
    ))}
  </ul>

ListItem.js

import React from 'react'
import RemoveTaskButton from './RemoveTaskButton'

export default props =>
  <>
    <li>
      <p contentEditable={true}>{props.title}</p>
    </li>
    <RemoveTaskButton onRemove={props.onRemove} />
  </>

InputText.js

import React from 'react'

export default props => <input type="text" value={props.value} onChange={props.onChange} />

AddTaskButton.js

import React from 'react'

export default props => <button onClick={props.onAdd}>Add task</button>

todo list exercise

import React from 'react'
import InputText from './InputText'
import List from './List'
import Button from './../clase1_2/Button'

class ListContainer extends React.Component {

  state = {
    todos: [{ id: 1, title: 'Ir a por el pan' }],
    newTodoText: ''
  }

  handleInputChange = e => {
    this.setState({ newTodoText: e.target.value })
  }

  onAddTodo = () => {
    this.setState(state => ({
      todos: [...state.todos, { id: Math.random(), title: state.newTodoText }],
      newTodoText: '',
    }))
  }

  onDeleteTask = (id) => {
    this.setState({ todos: this.state.todos.filter(todo => todo.id !== id) })
  }

  onEditTodo = (e, id) => {
    const value = e.target.value
    const todosEdited = this.state.todos.map(todo => {
      if (todo.id === id) todo.title = value
      return todo
    })
    this.setState({ todos: todosEdited })
  }

  render() {
    return (
      <>
        <List
          todos={this.state.todos}
          onDeleteTodo={this.onDeleteTask}
          onEditTodo={this.onEditTodo}
        />
        <InputText value={this.state.newTodoText} onChange={this.handleInputChange} />
        <Button onPress={this.onAddTodo}>Add todo</Button>
      </>
    )
  }

}

export default ListContainer

```js
const List = props => <ul>
  {props.todos.map(todo =>
    <li key={todo.id}>
      <input type="text" onChange={e => props.onEditTodo(e, todo.id)} value={todo.title} />
      <button onClick={() => props.onDeleteTodo(todo.id)}>Borrar</button>
    </li>
  )}
</ul>

export default List
const Button = (props) => <button onClick={props.onPress}>{props.children}</button>

export default Button
const InputText = props => <input type="text" value={props.value} onChange={props.onChange} />

export default InputText

main for hooks

import ShowDate from "../1-render/ShowDate";

import React, {useState} from 'react'
import ReplaceLetter from './ReplaceLetter'

function Main() {
    const [show, setShow] = useState(true)

    return (
        <>
            <button onClick={() => setShow(!show)}>toggle replace</button>
            {show && <ReplaceLetter />}
        </>
    )
}

export default Main

Forms

import React from 'react'
import CheckboxGroup from './CheckboxGroup'
export default props => 
    <>
        <label>Hobbies</label>
        <CheckboxGroup {...props} />
    </>
import React from 'react'

export default props => 
    <>
        {props.items.map((item) => (
            <span key={item}>
                <input checked={props.selectedItems.includes(item)} type="checkbox" onChange={props.onChange} value={item} />
                {item}
            </span>
        ))}
       
    </>
import React from 'react'
import InputText from './InputText'
import Textarea from './Textarea'
import GenderPicker from './GenderPicker'
import Select from './Select'
import ConditionalRender from './ConditionalRender'
import HobbiesPicker from './HobbiesPicker'
import CheckboxGroup from './CheckboxGroup'

export class Form extends React.Component {
    state = {
        name: '',
        firstname: '',
        description: '',
        gender: 'female',
        age: 27,
        selectedCountry: 'es',
        selectedProvince: 'guadalajara',
        selectedHobbies: ['games']
    }

    countries = [
        {
            value: 'es',
            text: 'Spain'
        },
        {
            value: 'usa',
            text: 'USA'
        }
    ]

    provinces = [
        {
            value: 'guadalajara',
            text: 'Guadalajara'
        },
        {
            value: 'madrid',
            text: 'Madrid'
        }
    ]

    hobbies = ['games', 'football', 'basketball', 'art']


    handleChangeInput = (e) => {
        this.setState({
            [e.target.name]: e.target.value
        })
    }

    printState = (e) => {
        console.log(this.state)
        e.preventDefault()
    }

    onChangeHobbies = (e) => {
        if (e.target.checked) {
            this.setState({ selectedHobbies: [...this.state.selectedHobbies, e.target.value] })
        } else {
            this.setState({ selectedHobbies: this.state.selectedHobbies.filter(hobby => hobby !== e.target.value) })
        }
    }

    render() {
        return(
            <form onSubmit={this.printState}>
                <InputText 
                    label="Name"
                    name="name"
                    value={this.state.name} 
                    onChange={this.handleChangeInput} 
                />
                <br />
                <InputText 
                    label="Firstname"
                    name="firstname"
                    value={this.state.firstname} 
                    onChange={this.handleChangeInput} 
                />
                <br />
                <Textarea 
                    value={this.state.description} 
                    onChange={this.handleChangeInput} 
                    name="description" 
                    label="Description"
                />
                <br />
                <GenderPicker 
                    onChange={this.handleChangeInput}
                    label="Gender"
                    value={this.state.gender}
                />
                <br />
                <InputText 
                    value={this.state.age} 
                    onChange={this.handleChangeInput}
                    type="number"
                    name="age" 
                    label="Age"
                />
                <br />
                <Select 
                    items={this.countries}
                    value={this.state.selectedCountry}
                    name="selectedCountry"
                    onChange={this.handleChangeInput}
                />
                <br />
                <ConditionalRender if={this.state.selectedCountry === 'es'}>
                    <Select 
                        items={this.provinces}
                        value={this.state.selectedProvince}
                        name="selectedProvince"
                        onChange={this.handleChangeInput}
                    />
                </ConditionalRender>
                <HobbiesPicker 
                    items={this.hobbies} 
                    onChange={this.onChangeHobbies}  
                    selectedItems={this.state.selectedHobbies} 
                />
                <button type="submit">Enviar</button>
            </form>
        )
    }
}

Component CallApi for hooks

import React, {useState, useEffect} from 'react'

function CallApi(props) {
    const [data, setData] = useState([])

    useEffect(() => {
        fetch('https://jsonplaceholder.typicode.com/todos')
            .then(response => response.json())
            .then(posts => setData(posts))
    }, [])

    return (
        <ul>
            {data.map((item) => (
                <li key={item.id}>{item.title}</li>
            ))}
        </ul>
    )
}

export default CallApi

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.