# React + Redux Workshop ###### tags: `f2e` ## Andy Tsai ## [線上ReactJS讀書會](https://www.facebook.com/groups/906048196159262/?ref=br_rs) --- ## Part I ### React 介紹 ### React 實作計數器 ## Part II ### Redux 介紹 ### 計數器加入 Redux --- ## StarterKit - [Github](https://github.com/bbandydd/React_Startkit) ``` npm install npm start ``` ---- ## 環境介紹 - ES6 + webpack + React + BABEL core ![](https://i.imgur.com/TyRyn9m.png) ---- ### ES6(ECMAScript 2015) ![](https://i.imgur.com/c351xIa.png) - Netscape公司將Javascript交給國際標準化組織ECMA,希望這種語言可以成國際標準 - 標準委員會最終決定,標準在每年6月正式發表一次,當作當年的正式版本 - ES6於2015年6月發佈,正式名稱就是ECMAScript 2015 ---- ### Babel ![](https://i.imgur.com/D8YYu0G.png) - Babel是一個轉碼器,可以將ES6轉成ES5 ---- ### Webpack ![](https://i.imgur.com/SGrvC8O.gif) - 前端模組管理和打包工具 - 將CSS、圖片與其他資源打包 - 預處理(SASS、JSX、ES6等)檔案 - 豐富的loader可以使用 --- ## Part I --- ## React 介紹 ---- ### Agenda - React 介紹 - Virtual DOM - JSX - State Management - Lifecycle ---- ### React [![](https://i.imgur.com/RFXwy1p.png)](http://reactjs.cn/react/index.html) - React is a declarative, efficient, and flexible JavaScript library for building user interfaces. ---- ### React 優點 - 組件化(Component)設計,利於Reuse - 用JSX進行UI設計 - 使用 Virtual DOM快速進行頁面重繪 - Component 就像個狀態機(State Machine),而且也有生命週期(Life Cycle) - 一律重繪(Always Redraw)和單向資料流 ---- ### what is DOM ### (Document Object Model) ---- ### This is HTML ``` <table> <tbody> <tr> <td>Shady Grove</td> <td>Aeolian</td> </tr> <tr> <td>Over the River, Charlie</td> <td>Dorian</td> </tr> </tbody> </table> ``` ---- ### and this is DOM ![](https://i.imgur.com/k0jTZhw.gif =700x400) ---- ### DOM feature - 直接操作DOM很慢 - [doc](https://leozdgao.me/why-dom-slow/) ---- ### Browser layout ```javascript= // Read var h1 = element1.clientHeight; // Write (invalidates layout) element1.style.height = (h1 * 2) + 'px'; // Read (triggers layout) var h2 = element2.clientHeight; // Write (invalidates layout) element2.style.height = (h2 * 2) + 'px'; // Read (triggers layout) var h3 = element3.clientHeight; // Write (invalidates layout) element3.style.height = (h3 * 2) + 'px'; ``` ---- ### Browser layout Even load element from DOM will cause layout event. ![](https://i.imgur.com/Wr93FEk.jpg) ---- ### Virtual DOM [reference](http://blog.reverberate.org/2014/02/react-demystified.html) ---- ### Vitrual DOM working flow ![](https://i.imgur.com/fNyP4MC.png) ---- ### React Component ``` class Hello extends React.Component{ constructor(props){ super(props) } render() { return (<div>Hello World</div>) } } ``` ---- ### JSX - 類似XML的語法 - 語意化的DOM宣告 - 更加簡潔 ---- JSX ```javascript= render() { return <div className="divider"> Label Text<hr /> </div> } ``` Plan JS ```javascript= render: function () { return React.DOM.div({className:"divider"}, "Label Text", React.DOM.hr() ); } ``` [Rules](https://facebook.github.io/react/docs/dom-elements.html) ---- ### JSX event ```javascript= class Hello extends React.Component{ handleClick = (event) => { // do something }; render() { return (<div onClick={this.handleClick}> click me </div>) } } ``` [event list](https://facebook.github.io/react/docs/events.html) ---- ### React State Management 1. props 2. state ---- ### Props - 父組件傳值至子組件(單向) ![](https://i.imgur.com/1X9Btfe.png) ---- ### Props ``` class Child extends React.Component { render(){ return ( <div> { this.props.children.map( (childName)=>(<div>{ childName }</div>) ) } </div> ) } } class Father extends React.Component { render(){ let childList = ['Nina', 'Ona', 'Bina'] return (<Child children={childList} />) } } ReactDOM.render(<Father/>, document.getElementById('app')) ``` ---- ### State - 整個Component當作一個狀態機(State Machine) - 一開始有個初始狀態,隨著使用者的互動會讓狀態改變,此時就會觸發讓 UI 重繪 (render) - 使用this.setState()更新state ---- ### State ```javascript= class TestStateComponent extends React.Component { constructor () { super(); this.state = { name: 'jack' }; } clickComp = () => { let new_state = { name: this.state.name + 'click' } this.setState(new_state); }; render () { return ( <div className="teststate-component" onClick={this.clickComp}> {this.state.name} </div> ); } } ``` ---- ### Stateless Component - React 1.4提供一種更簡單建立Component的方法 - [Stateless](https://medium.com/@housecor/react-stateless-functional-components-nine-wins-you-might-have-overlooked-997b0d933dbc#.xoho8qv6l) ---- ### React Component lifecycle - [Lifecycle](https://codepen.io/eduardoboucas/full/jqWbdb) ```javascript= class BookNormalComponent extends React.Component { componentDidMount(){ console.log('component first show in screen'); } render() { return ( <div className="booknormal-component"> Very Good </div> ) } } ``` ---- ### React Component Generator - [Github](https://github.com/bbandydd/React_Generator) - [DEMO](https://bbandydd.github.io/React_Generator/) --- ## React 實作計數器 ![](https://i.imgur.com/4rEyDYg.png) ---- ![](https://i.imgur.com/E72RMol.png) --- ## 放飯囉 ## 休息至13:00 --- ## Part II --- ## Redux 介紹 ---- ### Agenda - Why Redux - 單向資料流 - 三大原則 - Action - Reducer - Store ---- ### Redux 介紹 - Redux是單向資料流的概念,與React無關 - [jQuery with Redux](https://github.com/bbandydd/JQ_Redux) [![](https://i.imgur.com/V0uauZC.png)](http://redux.js.org/) ---- ### Why Redux - 網站需要管理比任何時候都要多的state(狀態) - state在什麼時候,由於什麼原因,如何變化已經不受控制 - React專注於View,卻沒有好的機制管理state - Redux就是讓管理state變得可預測 ![](https://i.imgur.com/BmVhCc5.png) ---- ### 單向資料流 <img src="https://i.imgur.com/X7UQTKr.gif" width="900px"/> ---- ### 三大原則 - Single source of truth (store) - State is read-only (action) - Changes are made with pure functions (reducer) ---- ### 1. Single source of truth (store) - 整個網站的state存在一個store裡 - 儲存state ``` { visibilityFilter: 'SHOW_ALL', todos: [ { text: 'Consider using Redux', completed: true, }, { text: 'Keep all state in a single tree', completed: false } ] } ``` ---- ### 2. State is read-only (action) - 唯一改變state的方法就是發送action - 傳送資料 ``` store.dispatch({ type: 'ADD_TODO', text }) ``` ---- ### 3. Changes are made with pure functions (reducer) - Reducer是pure function,接收舊的state和action,回傳新的state - 撰寫商業邏輯的地方 ``` function todos(state = [], action) { switch (action.type) { case 'ADD_TODO': return [ ...state, { text: action.text, completed: false } ] default: return state } } ``` ---- ## pure function ``` var xs = [1, 2, 3, 4, 5]; // pure(純) xs.slice(0, 3); //=> [1, 2, 3] xs.slice(0, 3); //=> [1, 2, 3] xs.slice(0, 3); //=> [1, 2, 3] ``` ---- ## impure function ``` // impure(不純) xs.splice(0, 3); //=> [1, 2, 3] xs.splice(0, 3); //=> [4, 5] xs.splice(0, 3); //=> [] ``` ---- ## Action - Action 從網站傳送資料至store - 它是更新store的唯一來源 - 使用store.dispatch()傳送資料 ``` { type: ADD_TODO, text } ``` ---- ## Action creator - Action creators 是產生action的function ``` function addTodo(text) { return { type: ADD_TODO, text } } ``` --- ## Reducer - Action 只負責傳送資料,卻未進行state修改 - Reducer就是負責撰寫邏輯並修改state的地方,最後回傳新的state ---- ## 不該在Reducer內做的事情 - 修改傳入的參數 - 執行API呼叫、Route跳轉 - 呼叫impure function, 如Date.now() or Math.random() ---- ## Handling Actions ``` function todos(state = [], action) { switch (action.type) { case ADD_TODO: return [ ...state, { text: action.text, completed: false } ] default: return state } } ``` ---- ## Store - Redux只有一個store - 使用store.getState()取得state - 使用dipatch(action)更新state - 使用subscribe(listener)註冊listener ---- ## createStore, combineReducers ``` import { createStore, combineReducers } from 'redux' import counter from 'counterReducer'; import todos from 'todosReducer'; const rootReducer = combineReducers({ counter, todos }) export default createStore(rootReducer) ``` ---- ## dispatch ``` store.dispatch(addTodo('todo1')) store.dispatch(addTodo('todo2')) store.dispatch(addTodo('todo3')) ``` ---- ### Redux 四步驟 1. store.dispatch(action) 2. reducer return new state 3. combine multiple reducers into a single state tree<br>(combineReducers) 4. Every listener registered with store.subscribe(listener) will now be invoked.<br>listeners may call store.getState() to get the current state<br>(connect -> react-redux) --- ### 計數器加入 Redux - [Repository](https://github.com/bbandydd/Redux_Count_Button) - [上課實作最終版](https://github.com/bbandydd/React_Startkit) ``` npm install --save redux react-redux ``` ---- ### 資料流 ![](https://i.imgur.com/tH9cG4m.png) ---- | | Presentational Components<br>(Dumb Component) | Container Components<br>(Smart Container) | | :---: | :---: | :---: | | 作用 | 畫面如何呈現 | 更新狀態 | | 使用Redux | No | Yes | | 資料來源 | Props | Redux state | | 修改資料 | 從props呼叫callback | Dispatch Redux actions| ---- ### Container and Component ![](https://i.imgur.com/KU1UMAF.png) ---- ### Create Container and Component ![](https://i.imgur.com/syrrw0g.png) ---- ### Create Container ``` + containers - Panel.js ``` - [containers](https://github.com/bbandydd/Redux_Count_Button/tree/master/src/containers) ---- ### Create Component ``` + components - Btn.js - Show.js ``` - [Components](https://github.com/bbandydd/Redux_Count_Button/tree/master/src/components) ---- ### Create Action ![](https://i.imgur.com/1tLVyQf.png) ---- ### Create Action ``` + actions - counterAction.js ``` - [actions](https://github.com/bbandydd/Redux_Count_Button/tree/master/src/actions) ---- ### Create Reducer ![](https://i.imgur.com/dz2lcuC.png) ---- ### Create Reducer ``` + reducers - counterReducer.js ``` - [reducers](https://github.com/bbandydd/Redux_Count_Button/tree/master/src/reducers) ---- ### Create Store ![](https://i.imgur.com/SyEfJae.png) ---- ### Create Store ``` + store - configureStore.js ``` - [store](https://github.com/bbandydd/Redux_Count_Button/tree/master/src/store) ---- ### Redux與View連接 ![](https://i.imgur.com/nU8F3ej.png) ---- ### connect - mapStateToProps() 將Redux store state放到props - mapDispatchToProps() 接收dispatch()並將callback放到props - 根據每個container放入所需state及action ``` export default connect(mapStateToProps, mapDispatchToProps)(Panel); ``` ---- ### curry ``` var add = function(x) { return function(y) { return x + y; }; }; add(1)(10); // 11 ``` ---- ### mapStateToProps ``` const mapStateToProps = (state) => { return { counterReducer: state.counterReducer } } ``` ---- ### mapDispatchToProps ``` const mapDispatchToProps = (dispatch) => { return { counterAction: bindActionCreators(counterAction, dispatch) } } ``` ---- ### Provider - 使用一個特殊的React Redux Component叫做<Provider>,它可以魔法般的讓全部container取得store - 只需要在root component使用一次就好 ``` <Provider store={configureStore}> <Panel /> </Provider> ``` --- ## Q & A
{"metaMigratedAt":"2023-06-14T12:12:53.772Z","metaMigratedFrom":"Content","title":"React + Redux Workshop","breaks":true,"contributors":"[{\"id\":\"e23ef62f-a089-4a28-8ce7-817212441f68\",\"add\":20,\"del\":0}]"}
    2115 views