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

Demystifying React, Redux, JSX and Webpack

Demystifying React, Redux, JSX and Webpack

The world of Javascript is vast and exciting... but it can also be quite scary! It is an innovative world in which new technologies appear all the time, which can make it difficult for developers to keep up to date.

Some of the most famous of these technologies are probably React and Redux. They changed the way we conceive User Interfaces, both in the browser and in mobile applications. But understanding them can be challenging: let's demystify them together so that you can enter the world of Javascript with confidence!

Titouan Galopin

March 28, 2019
Tweet

More Decks by Titouan Galopin

Other Decks in Programming

Transcript

  1. 10 Bidirectional data-binding An change in the model updates the

    view An change in the view updates the model
  2. View 18 Model Observable model Two-way data flow View React

    One-way data flow Store Dispatcher View
  3. 22 We want the benefits to blow the view away

    and re-render it ... … while dealing properly with every edge cases
  4. 27 A component = A description of a part of

    your UI that depends on your current model
  5. 31

  6. 36 Store Dispatcher View React handles the Dispatcher and the

    Store You only implement the view and define the structure of the Store
  7. 41

  8. 43 class Autocomplete extends Component { // ... render() {

    return ( <ul> {this.state.results.map(function(result) { return ( <li>{result.name}</li> ); })} </ul> ); } }
  9. 44 class Autocomplete extends Component { // ... render() {

    return ( <ul> {this.state.results.map(function(result) { return ( <li>{result.name}</li> ); })} </ul> ); } } Use of the state
  10. 45 class Autocomplete extends Component { // ... render() {

    return ( <ul> {this.state.results.map(function(result) { return ( <li>{result.name}</li> ); })} </ul> ); } } Use of the state To use a property: this.props.source
  11. State = Local data that will change over time Props

    = Non-local data, read-only for the component 46
  12. 48 class Autocomplete extends Component { // ... render() {

    return ( <ul> {this.state.results.map(function(result) { return ( <li>{result.name}</li> ); })} </ul> ); } }
  13. 49 class Autocomplete extends Component { // ... render() {

    return ( <ul> {this.state.results.map(function(result) { return ( <li>{result.name}</li> ); })} </ul> ); } } What’s that?!
  14. 50 JSX is a formatting language used by React to

    express a representation of views
  15. 52 class Autocomplete extends Component { // ... render() {

    return ( <ul> {this.state.results.map(function(result) { return ( <li>{result.name}</li> ); })} </ul> ); } } Not real HTML tags but components
  16. 58 class Autocomplete extends Component { // ... handleChange(event) {

    api.fetchResults(event.target.value).then(results => { this.setState({ results: results }) }); } // ... render() { return ( <div> <input type="text" onChange={this.handleChange} /> // ... </div> ); } }
  17. 66 Webpack is a build tool It lets you manipulate

    your Javascript and CSS before using it in production (JSX, minification, …)
  18. 67 Webpack Encore wraps Webpack around a nice API to

    improve its Developer Experience
  19. 71 // webpack.config.js const Encore = require( '@symfony/webpack-encore' ); Encore

    // ... .enableReactPreset(); module.exports = Encore.getWebpackConfig();
  20. 72 // app.js import ReactDOM from 'react-dom'; import {App} from

    './App.js'; ReactDOM.render( <App />, document.getElementById('portfolio') );
  21. 73 // app.js import ReactDOM from 'react-dom'; import {App} from

    './App.js'; ReactDOM.render( <App />, document.getElementById('portfolio') ); Tree of components
  22. 80 Redux helps you manage a single State for your

    whole application and use it in your components
  23. 86 Global state Initial global state Props View Props View

    Redux Component Component mapStateToProps
  24. 87 Global state Initial global state Dispatcher Props View Props

    View Redux Component Component mapStateToProps dispatch
  25. 88 Global state Initial global state Dispatcher Props View Props

    View Redux Component Component mapStateToProps dispatch Reducers
  26. 91

  27. 93

  28. 94

  29. 95

  30. 96 function mapStateToProps(globalState) { return { dateInterval: state.dateInterval, projects: state.projects,

    lastUpdated: state.lastUpdated, }; } class SidebarView extends Component { // ... } export const Sidebar = connect(mapStateToProps)(SidebarView);
  31. 97 function mapStateToProps(globalState) { return { dateInterval: state.dateInterval, projects: state.projects,

    lastUpdated: state.lastUpdated, }; } class SidebarView extends Component { // ... } export const Sidebar = connect(mapStateToProps)(SidebarView); Redux
  32. class SidebarView extends Component { // ... render() { return

    ( <div className="Sidebar"> <DateIntervalChooser currentValue={this.props.dateInterval} onChange={(i) => this.updateDateInterval(i)} /> <ul className="Sidebar-menu"> <li><Link to="/portfolio">All projects</Link></li> {this.props.projects.map( project => <SidebarItem project={project} /> )} </ul> <div className="Sidebar-last-updated"> Data last updated {moment(this.props.lastUpdated).fromNow()} </div> </div> ); 98
  33. 100 class SidebarView extends Component { updateDateInterval(interval) { this.props.dispatch({ type:

    'SET_DATE_INTERVAL', dateInterval: interval }); } // ... } Redux
  34. 101 import {storage} from '../storage/storage'; export const dateIntervalReducer = (state,

    action) => { if (typeof state === 'undefined') { return storage.get('portfolio-date-interval', 2); } switch (action.type) { case 'SET_DATE_INTERVAL': storage.set('portfolio-date-interval', action.dateInterval); return action.dateInterval; default: return state; } };
  35. 102 import {storage} from '../storage/storage'; export const dateIntervalReducer = (state,

    action) => { if (typeof state === 'undefined') { return storage.get('portfolio-date-interval', 2); } switch (action.type) { case 'SET_DATE_INTERVAL': storage.set('portfolio-date-interval', action.dateInterval); return action.dateInterval; default: return state; } }; Current state
  36. 103 import {storage} from '../storage/storage'; export const dateIntervalReducer = (state,

    action) => { if (typeof state === 'undefined') { return storage.get('portfolio-date-interval', 2); } switch (action.type) { case 'SET_DATE_INTERVAL': storage.set('portfolio-date-interval', action.dateInterval); return action.dateInterval; default: return state; } }; Current state Initial state
  37. 104 import {storage} from '../storage/storage'; export const dateIntervalReducer = (state,

    action) => { if (typeof state === 'undefined') { return storage.get('portfolio-date-interval', 2); } switch (action.type) { case 'SET_DATE_INTERVAL': storage.set('portfolio-date-interval', action.dateInterval); return action.dateInterval; default: return state; } }; Current state Initial state New state
  38. 105 import {combineReducers} from 'redux'; export const rootReducer = combineReducers({

    dateInterval: dateIntervalReducer, isLoading: isLoadingReducer, projects: projectsReducer, lastUpdated: lastUpdatedReducer, // ... });