React.js Workshop
淺入淺出 React.js
Denny Ku

我是誰
Denny Ku
- Sudo:Front-end developer
- 和沛科技:Front-end engineer
- github: abalone0204

今天要講什麼
- 為什麼 React 重要
- 基本的 React 教學
- 一般人懂的 React 教學

Outline
- 概念
- 簡介 MVC、MVVM
- What is React.js
- Pros & Cons
- 環境建置
- React basic
- Data flow
- State, Props, Life-cycle method
- React intermediate
- Router
- Redux
- Redux Saga
- CSS Modules

基本上
就是我的工作流程

概念
前言
- 每個人的定義的 MV* 可能都不一樣
- 去爭吵什麼是 Model 、什麼是 Controller 沒有意義
- 真正要在意的是這些想法在軟體架構上的意義

前言
- 可變與不可預測的狀態是萬惡之源
- 但需求永遠都是可變、不可預測的
所以我們應該消滅製造需求的人-
所以我們應該要在讓可變的狀態變得好預測
- Easy to reason about
- 好讀
- 符合常理

MVC 是什麼


MVVM 是什麼
多了一個 View Model


MVVM 是什麼
- ViewModel 不需要瞭解 View 的實作細節
- View 不需要知道 ViewModel 的實作細節,但是會聲明自己需要哪些數據、而且知道如何渲染畫面


所以
- 我們需要一個 ViewModel 來做 action binding
- 需要一個 state less 的 View

建置環境

建一個 React App

React Create App
$> npm install -g react-create-app
$> create-react-app hello-world
$> cd hello-world && npm install && npm start
React basic

f(Data, Template) = View
- 一個 Stateless 的 View 是什麼?
- Function 的特性:
- 好預測
Recap

- ViewModel 不需要瞭解 View 的實作細節
- View 不需要知道 ViewModel 的實作細節,但是會聲明自己需要哪些數據、而且知道如何渲染畫面

Thinking in React

- 如果你是個前端工程師,你會怎麼拆解這個畫面?


關鍵的概念:hierarchy
恰巧 HTML 最大的優點就是
它是個 markup languate
它能夠很好的描述各種 hierarchy

Component base

- 一次只要關注在一個小點上
- 決定這個 View 需要什麼樣的資料

Web Component

- HTML + JavaScript + CSS

<FilterableProductTable>
<SearchBar />
<ProductTable>
<ProductCategoryRow/>
<ProductRow/>
</ProductTable>
</FilterableProductTable>
JSX

- HTML + JavaScript + CSS

<FilterableProductTable>
<SearchBar />
<ProductTable>
<ProductCategoryRow/>
<ProductRow/>
</ProductTable>
</FilterableProductTable>
Hello world

// /static/js/bundle.js
import ReactDOM from 'react-dom';
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
<!doctype html>
<html lang="en">
<body>
<div id="example"></div>
</body>
<script type="text/javascript" src="/static/js/bundle.js"></script>
</html>

Hello world

// /static/js/bundle.js
import ReactDOM from 'react-dom';
import Hello from 'components/Hello';
ReactDOM.render(
<Hello />,
document.getElementById('example')
);
<!doctype html>
<html lang="en">
<body>
<div id="example"></div>
</body>
<script type="text/javascript" src="/static/js/bundle.js"></script>
</html>

const Hello = () => (
<h1>Hello, world!</h1>
);
export default Hello;
What is View

f (Data, Template) -> View
const Hello = () => (
<h1>Hello, world!</h1>
);
export default Hello;
const Hello = ({text}) => (
<h1>{text}</h1>
);
export default Hello;
f () -> View
React 中的 Props 跟 State

// CSS 待會再說
<Hello text={"yo"}/>
const Hello = ({text}) => (
<h1>{text}</h1>
);
export default Hello;
這就是 Props
那 State 呢

<div className="App">
<h1>Hello world</h1>
<input type="text" ref='input'/>
<button onClick={this.clickHandler}>
send
</button>
<TodoList todos={todos} />
</div>
clickHandler = (e) => {
const {
value,
} = this.refs.input
const {
todos,
} = this.state;
this.setState({
todos: todos.concat(value)
}, ()=> {
this.refs.input.value = '';
})
}
Live demo
State 的壞處
- 如果每一個小 component 都有自己的 state

State
State
State
State
gan gan gan

Make State great again

State
User action
還可以更好
這樣做的結果是會得到一個過度複雜的 Component


React intermediate

- 這裡會介紹這些東西在做什麼以及該怎樣學
Redux


Redux

- 優點:
- 沒有 local state 了
- functional way
- 好讀、好寫、好測試
- 會需要寫一些 boiler plate 的 code
- 不足的地方:
- 對於 Async 的 action 處理還不夠好
Redux - Async?

送出後不會馬上做完的事情

Redux - 學習資源

redux-saga

處理 Side effect、Async action 的 Middle ware
redux-saga - saga 是什麼


redux-saga - saga 是什麼


redux-saga - 學習資源

react-router

Single Page Application 的 Router 問題
關鍵概念:
If route is nested , then component should be nested.
CSS Modules

- local scope
- global scope
- composes
- 官方教學
CSS Modules


import cssModules from 'react-css-modules';
import styles from './styles.css';
/* eslint-disable global-require*/
const Loading = () => (
<div styleName="container">
<img
styleName="loading-icon"
src={require('../../../assets/components/loading-icon.png')} alt=""
/>
</div>
);
/* eslint-enable */
export default cssModules(Loading, styles);
@keyframes spin { 100% {transform: rotate(360deg); }}
.container {
position: relative;
padding: 30px;
text-align: center;
}
.loading-icon {
animation: spin 0.7s linear infinite;
}
CSS Modules

- 設置簡單
- 沒有 global 污染問題
- no more !important
- 符合組件的開發思想
CSS Modules - 結論

- 時間不夠了,總之讚讚讚
結論

- React 可能會收掉
- 但組件化的思想不會
- 可以了解底下怎麼做到的
- 但,越少需要寫 config 的東西最好
- 你可以 follow vuejs, cyclejs 等等 library
- 更好一點也可以 follow Reactive programming 的想法
- 也可以 follow 或我的網誌
結論

-
你使用的語言被人嘲笑
職業被藐視
解決問題的努力被視為噱頭
自詡不弄髒手的人輕視你面對的問題
執行引擎到處是實作者從未重視過的 Bug
所有跨平台的承諾都在增加你要解決的問題
UX認為要的效果很簡單
QA給你的回報難對上問題
最後,報酬通常低於平均水準你說,你想成為前端工程師
-
參考資料

淺入淺出我流 React.js
By Denny Ku
淺入淺出我流 React.js
- 2,581