Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Criando e Escalando com React & Redux & ...

Criando e Escalando com React & Redux & ...

Muitos começam com React criando pequenos componentes, depois passam a utilizar algum state management como o Redux, mas poucos param para pensar no quanto o código pode ficar confuso quando a aplicação cresce e passar a ter centenas/milhares de linhas de código. Nessa palestra mostrarei as práticas que venho seguindo nos últimos meses e que tem dado certo para os meus projetos.

willian

June 09, 2017
Tweet

More Decks by willian

Other Decks in Programming

Transcript

  1. COMEÇANDO QUANDO USAR REACT? ▸ Quando precisar que uma ou

    várias partes da sua página precise responder à ações do usuário
  2. COMEÇANDO QUANDO USAR REACT? ▸ Quando precisar que uma ou

    várias partes da sua página precise responder à ações do usuário ▸ Quando uma ou várias partes da sua página dependa de dados vindo do servidor através de uma requisição AJAX
  3. COMEÇANDO QUANDO USAR REACT? ▸ Quando precisar que uma ou

    várias partes da sua página precise responder à ações do usuário ▸ Quando uma ou várias partes da sua página dependa de dados vindo do servidor através de uma requisição AJAX ▸ Quando for criar um Single Page Application
  4. COMEÇANDO QUANDO USAR REACT? ▸ Quando precisar que uma ou

    várias partes da sua página precise responder à ações do usuário ▸ Quando uma ou várias partes da sua página dependa de dados vindo do servidor através de uma requisição AJAX ▸ Quando for criar um Single Page Application ▸ Quando pensar em usar jQuery (sic)
  5. COMEÇANDO QUANDO USAR REDUX? ▸ Quando precisar compartilhar o estado

    de um componente com um ou mais componentes ▸ Quando seus componentes estiverem muito complexos para gerenciar o estado utilizando métodos internos
  6. QUANDO USAR REDUX? EXEMPLO 1 1 import React, { Component

    } from 'react' 2 import './App.css' 3 4 import Counter from './counter' 5 import CounterValue from './counter-value' 6 7 class App extends Component { 8 render () { 9 return ( 10 <div className='app'> 11 <Counter /> 13 </div> 14 ) 15 } 16 } 17 18 export default App
  7. QUANDO USAR REDUX? EXEMPLO 1 1 import React, { Component

    } from 'react' 2 3 class Counter extends Component { 4 state = { value: 0 } 5 6 increment = () => { 7 this.setState(prevState => ({ 8 value: prevState.value + 1 9 })) 10 }; 11 12 decrement = () => { 13 this.setState(prevState => ({ 14 value: prevState.value - 1 15 })) 16 }; 17 18 render () { 19 return ( 20 <div className='counter'> 21 <h1>Current value: {this.state.value}</h1> 22 <button onClick={this.increment}>+</button> 23 <button onClick={this.decrement}>-</button> 24 </div> 25 ) 26 } 27 } 28 29 export default Counter 1 import React, { Component } from 'react' 2 import './App.css' 3 4 import Counter from './counter' 5 import CounterValue from './counter-value' 6 7 class App extends Component { 8 render () { 9 return ( 10 <div className='app'> 11 <Counter /> 13 </div> 14 ) 15 } 16 } 17 18 export default App
  8. QUANDO USAR REDUX? EXEMPLO 2 1 import React, { Component

    } from 'react' 2 3 import CounterResult from './counter-result' 4 import CounterControl from './counter-control' 5 6 class Counter extends Component { 7 state = { value: 0 } 8 9 increment = () => { 10 this.setState(prevState => ({ 11 value: prevState.value + 1 12 })) 13 }; 14 15 decrement = () => { 16 this.setState(prevState => ({ 17 value: prevState.value - 1 18 })) 19 }; 20 21 render () { 22 return ( 23 <div className='counter'> 24 <CounterResult value={this.state.value} /> 25 <CounterControl increment={this.increment} decrement={this.decrement} /> 26 </div> 27 ) 28 } 29 } 30 31 export default Counter
  9. QUANDO USAR REDUX? EXEMPLO 2 1 import React, { Component

    } from 'react' 2 3 import CounterResult from './counter-result' 4 import CounterControl from './counter-control' 5 6 class Counter extends Component { 7 state = { value: 0 } 8 9 increment = () => { 10 this.setState(prevState => ({ 11 value: prevState.value + 1 12 })) 13 }; 14 15 decrement = () => { 16 this.setState(prevState => ({ 17 value: prevState.value - 1 18 })) 19 }; 20 21 render () { 22 return ( 23 <div className='counter'> 24 <CounterResult value={this.state.value} /> 25 <CounterControl increment={this.increment} decrement={this.decrement} /> 26 </div> 27 ) 28 } 29 } 30 31 export default Counter 1 import React from 'react' 2 3 const CounterResult = ({ value }) => ( 4 <h1>Current value: {value}</h1> 5 ) 6 7 export default CounterResult
  10. QUANDO USAR REDUX? EXEMPLO 2 1 import React, { Component

    } from 'react' 2 3 import CounterResult from './counter-result' 4 import CounterControl from './counter-control' 5 6 class Counter extends Component { 7 state = { value: 0 } 8 9 increment = () => { 10 this.setState(prevState => ({ 11 value: prevState.value + 1 12 })) 13 }; 14 15 decrement = () => { 16 this.setState(prevState => ({ 17 value: prevState.value - 1 18 })) 19 }; 20 21 render () { 22 return ( 23 <div className='counter'> 24 <CounterResult value={this.state.value} /> 25 <CounterControl increment={this.increment} decrement={this.decrement} /> 26 </div> 27 ) 28 } 29 } 30 31 export default Counter 1 import React from 'react' 2 3 const CounterResult = ({ value }) => ( 4 <h1>Current value: {value}</h1> 5 ) 6 7 export default CounterResult 1 import React from 'react' 2 3 const CounterControl = ({ increment, decrement }) => ( 4 <div className='control'> 5 <button onClick={increment}>+</button> 6 <button onClick={decrement}>-</button> 7 </div> 8 ) 9 10 export default CounterControl
  11. QUANDO USAR REDUX? EXEMPLO 3 1 import React, { Component

    } from 'react' 2 import './App.css' 3 4 import Counter from './counter' 5 import CounterValue from './counter-value' 6 7 class App extends Component { 8 render () { 9 return ( 10 <div className='app'> 11 <Counter /> 12 <CounterValue /> 13 </div> 14 ) 15 } 16 } 17 18 export default App
  12. QUANDO USAR REDUX? EXEMPLO 3 1 import React, { Component

    } from 'react' 2 3 import CounterResult from './counter-result' 4 import CounterControl from './counter-control' 5 6 class Counter extends Component { 7 state = { value: 0 } 8 9 increment = () => { 10 this.setState(prevState => ({ 11 value: prevState.value + 1 12 })) 13 }; 14 15 decrement = () => { 16 this.setState(prevState => ({ 17 value: prevState.value - 1 18 })) 19 }; 20 21 render () { 22 return ( 23 <div className='counter'> 24 <CounterResult value={this.state.value} /> 25 <CounterControl increment={this.increment} decrement={this.decrement} /> 26 </div> 27 ) 28 } 29 } 30 31 export default Counter
  13. QUANDO USAR REDUX? EXEMPLO 3 1 import React, { Component

    } from 'react' 2 3 import CounterResult from './counter-result' 4 import CounterControl from './counter-control' 5 6 class Counter extends Component { 7 state = { value: 0 } 8 9 increment = () => { 10 this.setState(prevState => ({ 11 value: prevState.value + 1 12 })) 13 }; 14 15 decrement = () => { 16 this.setState(prevState => ({ 17 value: prevState.value - 1 18 })) 19 }; 20 21 render () { 22 return ( 23 <div className='counter'> 24 <CounterResult value={this.state.value} /> 25 <CounterControl increment={this.increment} decrement={this.decrement} /> 26 </div> 27 ) 28 } 29 } 30 31 export default Counter 1 import React, { Component } from 'react' 2 3 class CounterValue extends Component { 4 state = { value: 0 } 5 render () { 6 return ( 7 <div className='counter-value'> 8 <h2>Counter value: {this.state.value}</h2> 9 </div> 10 ) 11 } 12 } 13 14 export default CounterValue
  14. FUNCTION FIRST ├── actions │ ├── cart-actions.js │ ├── product-actions.js

    │ └── session-actions.js ├── components │ ├── cart-item.jsx │ ├── footer.jsx │ ├── header.jsx │ ├── login-form.jsx │ ├── product-box.jsx │ ├── product-buttons.jsx │ └── register-form.jsx ├── containers │ ├── home.jsx │ ├── product-details.jsx │ ├── product-list.jsx │ └── shopping-cart.jsx └── reducers ├── cart-reducers.js ├── product-reducers.js └── session-reducers.js
  15. FUNCTION FIRST ├── actions │ ├── cart-actions.js │ ├── product-actions.js

    │ └── session-actions.js ├── components │ ├── cart-item.jsx │ ├── footer.jsx │ ├── header.jsx │ ├── login-form.jsx │ ├── product-box.jsx │ ├── product-buttons.jsx │ └── register-form.jsx ├── containers │ ├── home.jsx │ ├── product-details.jsx │ ├── product-list.jsx │ └── shopping-cart.jsx └── reducers ├── cart-reducers.js ├── product-reducers.js └── session-reducers.js FEATURE FIRST ├── cart │ ├── cart-actions.js │ ├── cart-item.jsx │ ├── cart-reducers.js │ └── shopping-cart.jsx ├── common │ ├── footer.jsx │ ├── header.jsx │ └── home.jsx ├── product │ ├── product-actions.js │ ├── product-box.jsx │ ├── product-buttons.jsx │ ├── product-details.jsx │ ├── product-list.jsx │ └── product-reducers.js └── session ├── login-form.jsx ├── register-form.jsx ├── session-actions.js └── session-reducers.js
  16. O MELHOR DOS DOIS MUNDOS ├── assets │ ├── fonts

    │ ├── images │ └── stylesheets ├── modules │ ├── cart │ ├── product │ └── session ├── utils │ ├── api.js │ └── is-mobile.js ├── views │ ├── components │ │ ├── footer.jsx │ │ └── header.jsx │ └── page │ ├── cart │ ├── product │ └── session │ └── components │ ├── sign-in │ └── sign-up ├── index.js ├── reducers.js ├── routes.js ├── sagas.js └── store.js
  17. A PROPOSAL FOR BUNDLING REDUCERS, ACTION TYPES AND ACTIONS WHEN

    USING REDUX Erik Rasmussen (https://github.com/erikras/ducks-modular-redux) DUCKS
  18. CONJUNTO DE ARQUIVOS QUE JUNTOS DEFINEM REDUXERS, ACTIONS, TYPES E

    TUDO MAIS QUE UM MÓDULO PRECISA TER PARA RODAR COM REDUX. MODULES CONJUNTO DE ARQUIVOS QUE JUNTOS DEFINEM REDUCERS, ACTION CREATORS, TYPES, SAGAS E TUDO MAIS QUE UM MÓDULO PRECISA TER PARA RODAR COM REDUX.
  19. DEFININDO MÓDULOS ├── cart │ ├── action-creators.js │ ├── action-types.js

    │ ├── index.js │ ├── reducers.js │ └── sagas.js └── product ├── action-creators.js ├── action-types.js ├── index.js ├── reducers.js ├── requests.js └── sagas.js
  20. MÓDULOS REGRAS PARA CRIAR UM MÓDULO ├── cart │ ├──

    action-creators.js │ ├── action-types.js │ ├── index.js │ ├── reducers.js │ └── sagas.js └── product ├── action-creators.js ├── action-types.js ├── index.js ├── reducers.js ├── requests.js └── sagas.js
  21. MÓDULOS REGRAS PARA CRIAR UM MÓDULO ▸ index.js ├── cart

    │ ├── action-creators.js │ ├── action-types.js │ ├── index.js │ ├── reducers.js │ └── sagas.js └── product ├── action-creators.js ├── action-types.js ├── index.js ├── reducers.js ├── requests.js └── sagas.js
  22. MÓDULOS REGRAS PARA CRIAR UM MÓDULO ▸ index.js ▸ DEVE

    exportar uma função chamada reducer como default ├── cart │ ├── action-creators.js │ ├── action-types.js │ ├── index.js │ ├── reducers.js │ └── sagas.js └── product ├── action-creators.js ├── action-types.js ├── index.js ├── reducers.js ├── requests.js └── sagas.js
  23. MÓDULOS REGRAS PARA CRIAR UM MÓDULO ▸ index.js ▸ DEVE

    exportar uma função chamada reducer como default ▸ DEVE exportar os "action creators" ├── cart │ ├── action-creators.js │ ├── action-types.js │ ├── index.js │ ├── reducers.js │ └── sagas.js └── product ├── action-creators.js ├── action-types.js ├── index.js ├── reducers.js ├── requests.js └── sagas.js
  24. MÓDULOS REGRAS PARA CRIAR UM MÓDULO ▸ index.js ▸ DEVE

    exportar uma função chamada reducer como default ▸ DEVE exportar os "action creators" ▸ DEVE definir "action types" no formato REDUCER/ACTION_TYPE ├── cart │ ├── action-creators.js │ ├── action-types.js │ ├── index.js │ ├── reducers.js │ └── sagas.js └── product ├── action-creators.js ├── action-types.js ├── index.js ├── reducers.js ├── requests.js └── sagas.js
  25. MÓDULOS REGRAS PARA CRIAR UM MÓDULO ▸ index.js ▸ DEVE

    exportar uma função chamada reducer como default ▸ DEVE exportar os "action creators" ▸ DEVE definir "action types" no formato REDUCER/ACTION_TYPE ▸ Arquivos opcionais: ├── cart │ ├── action-creators.js │ ├── action-types.js │ ├── index.js │ ├── reducers.js │ └── sagas.js └── product ├── action-creators.js ├── action-types.js ├── index.js ├── reducers.js ├── requests.js └── sagas.js
  26. MÓDULOS REGRAS PARA CRIAR UM MÓDULO ▸ index.js ▸ DEVE

    exportar uma função chamada reducer como default ▸ DEVE exportar os "action creators" ▸ DEVE definir "action types" no formato REDUCER/ACTION_TYPE ▸ Arquivos opcionais: ▸ requests.js ├── cart │ ├── action-creators.js │ ├── action-types.js │ ├── index.js │ ├── reducers.js │ └── sagas.js └── product ├── action-creators.js ├── action-types.js ├── index.js ├── reducers.js ├── requests.js └── sagas.js
  27. MÓDULOS REGRAS PARA CRIAR UM MÓDULO ▸ index.js ▸ DEVE

    exportar uma função chamada reducer como default ▸ DEVE exportar os "action creators" ▸ DEVE definir "action types" no formato REDUCER/ACTION_TYPE ▸ Arquivos opcionais: ▸ requests.js ▸ utils.js ├── cart │ ├── action-creators.js │ ├── action-types.js │ ├── index.js │ ├── reducers.js │ └── sagas.js └── product ├── action-creators.js ├── action-types.js ├── index.js ├── reducers.js ├── requests.js └── sagas.js
  28. MÓDULOS REGRAS PARA CRIAR UM MÓDULO ▸ index.js ▸ DEVE

    exportar uma função chamada reducer como default ▸ DEVE exportar os "action creators" ▸ DEVE definir "action types" no formato REDUCER/ACTION_TYPE ▸ Arquivos opcionais: ▸ requests.js ▸ utils.js É possível definir action creators, action types e reducers dentro de um único arquivo chamado index.js, mas acredito que separar em vários arquivos mantém a leitura da estrutura do projeto mais simples e fácil de entender. ├── cart │ ├── action-creators.js │ ├── action-types.js │ ├── index.js │ ├── reducers.js │ └── sagas.js └── product ├── action-creators.js ├── action-types.js ├── index.js ├── reducers.js ├── requests.js └── sagas.js
  29. REDUX-SAGA IS A LIBRARY THAT AIMS TO MAKE SIDE EFFECTS

    IN REACT/REDUX APPLICATIONS EASIER AND BETTER. https://github.com/redux-saga/redux-saga REDUX-SAGA
  30. A SIDE EFFECT MODIFIES THE OUTSIDE WORLD. EVERYTHING IN YOUR

    APP THAT DEALS WITH MAKING HTTP REQUESTS, WRITING TO LOCALSTORAGE, OR EVEN MANIPULATING THE DOM, IS CONSIDERED A SIDE EFFECT. SIDE EFFECTS Luca Matteis (http://wfernand.es/2o)
  31. ES6 GENERATORS EXEMPLO 1 function * foo() { 2 yield

    1 3 yield 2 4 yield 3 5 yield 4 6 yield 5 7 }
  32. ES6 GENERATORS EXEMPLO 1 function * foo() { 2 yield

    1 3 yield 2 4 yield 3 5 yield 4 6 yield 5 7 } 1 const it = foo() 2 3 console.log(it.next())
  33. ES6 GENERATORS EXEMPLO 1 function * foo() { 2 yield

    1 3 yield 2 4 yield 3 5 yield 4 6 yield 5 7 } 1 const it = foo() 2 3 console.log(it.next()) 1 const it = foo() 2 3 console.log(it.next()) // { value: 1, done: false }
  34. ES6 GENERATORS EXEMPLO 1 function * foo() { 2 yield

    1 3 yield 2 4 yield 3 5 yield 4 6 yield 5 7 } 1 const it = foo() 2 3 console.log(it.next()) 1 console.log(it.next()) // { value: 2, done: false } 2 console.log(it.next()) // { value: 3, done: false } 3 console.log(it.next()) // { value: 4, done: false } 4 console.log(it.next()) // { value: 5, done: false } 4 console.log(it.next()) // { value: undefined, done: true } 1 const it = foo() 2 3 console.log(it.next()) // { value: 1, done: false }