Skip to content

Commit dffbdb5

Browse files
committed
update tuts
1 parent 5c5e9c4 commit dffbdb5

File tree

2 files changed

+127
-46
lines changed

2 files changed

+127
-46
lines changed

docs/src/main/tut/Fantasy.md

Lines changed: 83 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ position: 3
77

88
# XReact Fantasy
99

10-
xreact is already a Functional library that can integrete FRP lib rxjs or mostjs into react. But it's still too many details you need to care while modeling UI components.
10+
xreact is a Functional library that can integrete FRP lib rxjs or mostjs into react. But there're still too many details you need to care while modeling UI components.
1111

1212
The implement of [Fantasy Land](https://github.com/fantasyland/fantasy-land), which will change the way you model and implement UI entirely.
1313

@@ -25,66 +25,110 @@ lift(x=>x+1)([1,2,3]) // => [2,3,4]
2525

2626
You should notice that both lift and map transform `x => x + 1` which should only able to apply to `Number`, to a function that can apply to `Array[Number]`
2727

28-
We can now (from v2.3.0) lift a normal function to xReact as well.
28+
We can now (from v2.3.0) lift a normal function to which can apply to xReact FantasyX as well.
2929

30-
Let's take BMI calculator for example.
31-
32-
the key business logic of a BMI calculator is very simple
30+
Let's take a look at a really simple example, multiply 2 numbers.
3331

3432
```js
35-
function calcBMI(weight, height) {
36-
let bmi = 0
37-
let health = '...'
38-
if (height && weight) {
39-
bmi = height / (weight * weight)
40-
}
41-
if (bmi < 18.5) health = 'underweight'
42-
else if (bmi < 24.9) health = 'normal'
43-
else if (bmi < 30) health = 'Overweight'
44-
else health = 'Obese'
45-
return { bmi: bmi.toString(), health }
33+
// Number -> Number -> Number
34+
function mult(a, b) {
35+
return a * b
4636
}
37+
mult(1, 2)
4738
```
4839

49-
The implementation doesn't seem to very Functional, but it doesn't matter since it's very low level implementation. It's a very easy to use, pure function:
40+
But if we need a React Component that multiply 2 numbers from 2 input box, how complicated it could be?
41+
42+
Now you get simply get a free FantasyX from just any normal function, via `lift`.
5043

5144
```js
52-
calcBMI(65, 1.72)
53-
// => Object { bmi: "23.661438615467823", health: "normal" }
45+
// FantasyX -> FantasyX -> FantasyX
46+
let xMult = lift2(mult)
5447
```
5548

56-
Now we have a pretty simple function that can calc BMI and return health level and bmi score.
49+
`mult` need 2 arguments, that's why we use `lift2` here.
50+
5751

58-
How can we lift this function and make the exactly same functional React Component then?
52+
Now that we have on function `xMult` that can turn 2 FantasyX into one, lets do this:
5953

6054
```js
61-
let xplan = lift2(calcBMI)(xinput('weight'), xinput('height'))
55+
let XMult = xMult(xinput('a'), xinput('b'))
6256
```
6357

64-
Now we have a `xplan` of type `FantasyX`, simply apply it to a View and then you will get a React Component.
58+
and we got a new FantasyX `XMult` with the computation built in.
59+
60+
`xinput` is an FantasyX abstraction of input box.
61+
62+
All we have so far was just a FantasyX `XMult` with computation composed inside, and we need a View to display and interact with. Here comes a really simple Stateless Component
6563

6664
```js
67-
let View = props => (
65+
const View = props => (
6866
<div>
69-
<label>
70-
weight(kg):
71-
<input type="number" name="weight" defaultValue="0" onChange={props.actions.fromEvent} />
72-
</label>
73-
<label>
74-
height(m):
75-
<input type="number" name="height" defaultValue="0" onChange={props.actions.fromEvent} />
76-
</label>
77-
<p>Your BMI is <b>{props.bmi}</b></p>
78-
<p>which means you're <b>{props.health}</b></p>
67+
<input name="a" onChange={props.actions.fromEvent} defaultValue={props.a}/>
68+
<input name="b" onChange={props.actions.fromEvent} defaultValue={props.b}/>
69+
<div>{props.output}</div>
7970
</div>
8071
)
81-
let BMICalc = xplan.apply(View)
72+
View.defaultProps = { a: "", b: "",output:""}
8273
```
8374

84-
Check out the Calculator:
75+
apply XMult to View then we'll get a React Component
8576

86-
<iframe src="https://www.webpackbin.com/bins/-Ksaj0iHMWD2xC24bAqR" frameborder="0" width="100%" height="500"></iframe>
77+
```js
78+
let Mult = XMult.apply(View)
79+
```
80+
81+
<https://www.webpackbin.com/bins/-KoGxSJ-3pOi4DicUvaq>
82+
83+
<iframe src="https://www.webpackbin.com/bins/-KoGxSJ-3pOi4DicUvaq" frameborder="0" width="100%" height="500"></iframe>
84+
85+
## Functor
86+
87+
FantasyX also implemented Functor, so we can transform one FantasyX to another
88+
89+
For example, from `XMult`, we could simply transform it into a `XMMP` with new computation
90+
91+
```js
92+
let XMMP = XMult.map((s) => ({output: s.output * s.output}))
93+
```
94+
95+
it's just like maping on a list
96+
97+
```js
98+
[1,2,3].map(x=>x*x)
99+
// [2,4,6]
100+
```
101+
102+
<https://www.webpackbin.com/bins/-Kss6m5ORK74CObhAPqB>
103+
104+
<iframe src="https://www.webpackbin.com/bins/-Kss6m5ORK74CObhAPqB" frameborder="0" width="100%" height="500"></iframe>
105+
106+
## Monoid
107+
108+
It's actually Semigroup, but if we have a ID FantasyX, we have Monoid, a Identity FantasyX make sense in that the computation inside is just Identity.
109+
110+
Anyway, let's see how can we combine two FantasyX together
111+
112+
```js
113+
let XCOMBINE = XMMP.concat(XMult)
114+
```
115+
116+
仅此, 我们就得到了一个同时具有 XMMP 与 XMult 行为的 FantasyX
87117

88-
## `FantasyX`
118+
当然, 因为他们都会修改 `state.output`, 合并到一起会导致冲突, 我们稍微修改下 XMMP
89119

90-
``FantasyX` implement `Applicative`, `Monoid`,
120+
```js
121+
let XMMP = XMult.map((s) => ({output2: s.output * s.output}))
122+
```
123+
124+
nothing special just like how you concat two Arrays
125+
126+
<https://www.webpackbin.com/bins/-Kss6m5ORK74CObhAPqB>
127+
128+
<iframe src="https://www.webpackbin.com/bins/-Kss6m5ORK74CObhAPqB" frameborder="0" width="100%" height="500"></iframe>
129+
130+
-------
131+
132+
Check out a more complicated BMI Calculator:
133+
134+
<iframe src="https://www.webpackbin.com/bins/-Ksaj0iHMWD2xC24bAqR" frameborder="0" width="100%" height="500"></iframe>

docs/src/main/tut/React-Most-函数式最佳实践.md

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ section: zh
1111

1212
先来初级的函数式重构
1313

14-
使用 union-type 定义 `Intent`
15-
-----------------------------
14+
JavaScript Union Types
15+
---------------
16+
17+
### 使用 Union Type 定义 `Intent`
1618

1719
[union-type](https://github.com/paldepind/union-type) 是一个简单的提供 union type,或者说 case class 的库。
1820

@@ -34,8 +36,7 @@ export default Type({
3436
})
3537
```
3638

37-
case Intent, 别 switch
38-
----------------------
39+
### case Intent, 别 switch
3940

4041
case union-type 是 pattern matching, 不是 switch case
4142

@@ -56,8 +57,7 @@ const counterable = connect(intent$ => {
5657
})
5758
```
5859

59-
pattern match union type
60-
------------------------
60+
### pattern match union type
6161

6262
union type 还可以带上值,比如 `Inc` 的内容是 `Number`
6363

@@ -88,6 +88,42 @@ const counterable = connect(intent$ => {
8888
})
8989
```
9090

91+
TypeScript Union Types
92+
----------------------
93+
使用 TypeScript 的 Union Type 会简单得多, 而且运行时是zero cost, 只会在编译时检查.
94+
95+
```ts
96+
export interface Inc {
97+
kind: 'inc'
98+
}
99+
export interface Dec {
100+
kind: 'dec'
101+
}
102+
export type Intent = Inc | Dec
103+
```
104+
105+
稍微缺陷的是 TypeScript 没有 pattern matching
106+
107+
```ts
108+
const counterable = x<"Observable", Intent, State>(intent$ => {
109+
return {
110+
update$: intent$.map(intent =>{
111+
switch(intent.kind) {
112+
case 'inc': return state => ({count: state.count + 1})
113+
case 'dec': return state => ({count: state.count + 1})
114+
default: return state => state'
115+
}
116+
}),
117+
actions: {
118+
inc: () => ({kind: 'inc'} as Inc),
119+
dec () => ({kind: 'dec'} as Dec)
120+
}
121+
}
122+
})
123+
```
124+
125+
但是没关系, 编译器会保证你case的类型正确, 比如你在case 里写错类型的字符串如 `incblahblah`, 编译不会通过.
126+
91127
lens
92128
----
93129
@@ -99,7 +135,7 @@ lens 是 composable, immutable, functional 的更新,观察数据结构的方
99135
import {lens, over, inc, dec, identity} from 'ramda'
100136
const counterable = connect(intent$ => {
101137
let lensCount = lens(prop('count'))
102-
return {
138+
return {
103139
sink$: intent$.map(Intent.case({
104140
Inc: () => over(lensCount, inc)
105141
Dec: () => over(lensCount, dec),
@@ -188,6 +224,7 @@ const CounterView = props => (
188224
189225
现在我们的Counter 就变成了[这样](https://github.com/reactive-react/react-most/blob/master/examples/frp-counter/src/app.jsx)
190226
227+
191228
搞基
192229
====
193230

0 commit comments

Comments
 (0)