# 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}]"}