舉例來說:
所有可互動的都有狀態
feat. 冠群的 slide
先由使用者互動改變狀態
畫面會依據不同的狀態去顯示
管理 資料 和 使用者操作事件 的互動流程
一個可預測的狀態容器
單向資料流
將狀態視作一連串的狀態流
每次的事件都是產生一個新的狀態
雙向資料綁定 → 連鎖更新
不容易去預測一個單一互動所造成的改變結果
MVC 只定義了三個角色的功能與關係
有了 FLUX 能更明確的定義「與資料互動的方式」
Single Store : Single Source of Truth
Finite State Machine (FSM) & Statechart based
有限個狀態以及在這些狀態之間的轉移和動作等行為的數學模型
例如:紅綠燈
( FSM 是很嚴謹的模型,這邊只是粗淺介紹 )
簡言之 就是 定義 各狀態 ( State ) 和 過渡方法 ( Action )
import React from 'react';
import { useMachine } from '@xstate/react';
import { lightMachine } from './lightMachine';
function App() {
const [state, send] = useMachine(lightMachine);
return (
<div className="App">
{state.matches(LIGHT_STATES.RED) && <RedLight />}
{state.matches(LIGHT_STATES.GREEN) && <GreenLight />}
{state.matches(LIGHT_STATES.YELLOW) && <YellowLight />}
<button
onClick={() => {
send(LIGHT_EVENTS.CLICK);
}}
>
click me
</button>
</div>
);
}
import { Machine } from 'xstate';
const LIGHT_STATES = {
RED: 'RED',
GREEN: 'GREEN',
YELLOW: 'YELLOW',
};
const LIGHT_EVENTS = {
CLICK: 'CLICK',
};
export const lightMachine = Machine({
initial: LIGHT_STATES.RED,
states: {
[LIGHT_STATES.RED]: {
on: {
[LIGHT_EVENTS.CLICK]: LIGHT_STATES.GREEN,
},
},
[LIGHT_STATES.GREEN]: {
on: {
[LIGHT_EVENTS.CLICK]: LIGHT_STATES.YELLOW,
},
},
[LIGHT_STATES.YELLOW]: {
on: {
[LIGHT_EVENTS.CLICK]: LIGHT_STATES.RED,
},
},
},
});
資料改變 或 使用者觸發事件 後產生的後續影響
運算的過程中,改變了系統狀態或是對外部世界進行交互。
如:非同步請求( Network Request )而產生的資料不一致
本身自己不處理 Side Effect,依賴於 其他套件處理 ( middleware )
import {
createStore,
combineReducers,
compose,
applyMiddleware,
} from 'redux';
import thunk from 'redux-thunk';
const store = createStore(combineReducers({
}), {}, compose(
applyMiddleware(
thunk,
),
));
export default store;
優
優
缺
缺
One More Thing
Flow Control in FSM
Shopping
Login
Payment
Pending
Success
idle
type Payload =
| {
step: 'idle';
}
| PayloadShopping
| PayloadLogin
| PayloadPayment
| PayloadPending
| PayloadSucess;
interface PayloadShopping {
step: 'shopping';
customerInfo: CustomerInfo | undefined;
items: ShoppingCartItemData[];
}
interface PayloadLogin extends Omit<PayloadShopping, 'step'> {
step: 'login';
}
interface PayloadPayment extends Omit<PayloadLogin, 'step'> {
accessToken: string;
step: 'payment';
}
interface PayloadPending extends Omit<PayloadPayment, 'step'> {
receivedAmount: number;
step: 'pending';
}
interface PayloadSucess extends Pick<PayloadPending, 'receivedAmount'> {
payment: CheckoutCashPaymentMutation_payment;
step: 'success';
}
{payload.step === 'idle' && (
<EnterCustomerNoModal
onNextStep={...}
/>
)}
{payload.step === 'shopping' && (
<Shopping
payload={...}
onGoBack={...}
onCheckout={...}
/>
}
{payload.step === 'login' && (
<Login
payload={...}
onGoBack={...}
onCheckout={...}
/>
)}
{payload.step === 'payment' && (
<Payment
payload={...}
onGoBack={...}
onPayment={...}
/>
)}
{payload.step === 'pending' && (
<Pending
payload={...}
onGoBack={...}
onSuccess={...}
/>
)}
{payload.step === 'success' && (
<Success
payload={...}
onGoBack={...}
onOk={...}
/>
)}