最开始接触 Redux 时候做 demo 时候只是照猫画虎将 redux 进入到 react 项目来使用,其实我们平时开发时候大部分时间都是在画流程图和实现功能,我们往往忽略了代码可测试的重要性。只是在编码和调试代码频繁切换。随着不断新增的功能,应用变得复杂,我们在调试话费的时间也要远远大于开发的时间。即使一个小小功能更新或修改,都需要大量时间调试和测试。
这个时候也是考验的框架设计的时候,好的框架一定要考虑可测试和可扩展。可能对于刚刚入门的 developer 并不能很好理解,慢慢来吧。
无论是 web 前端开发还是 Android 应用开发,我们应用就是一部可以交互的电影,剧情是导演和观众决定。其实我们每天看到的和感受到的难道不是电影吗?一张张连续画面呈现给用户来引导用户的行为,画面的背后是一个一个的数据。界面只是更友好地把用户需要数据呈现给用户以便他阅读和消费。其实我们可以做更简单粗暴些,直接将数据显示给用户。
这就是我们 web 或是 Android 前端主要工作,我们是把枯燥的数据以一种人性化方式呈现给用户,或甚至可以说一种艺术行为。
redux好回到到整体说说今天的主角 redux。
每一个界面我们都可以用数据来进行描述。这些描述界面数据模型我们可以理解为应用状态,其实我们不要想的太复杂,状态、数据以及视图其实本质都是一个,那就是数据。
然后就是交互,交互就是用户对应用发起指令也就是动作(action),操作可以是点击、下滑、拖动或者是语言。这些都是来自用户的动作,应用接收这些动作 action 通过一个存函数将一个一个的动作对应到状态也就是数据上,这就是 reducer 这个存函数的作用,输入 action 输出状态(store),store 发生了变化我们需要将 store 翻译成界面表达给用户。其实这是一个副作用,我们可以用订阅方式来让界面(view)来和视图进行绑定。当视图关心的数据发生改变了,视图也随之改变。
store
这里代码大家暂时作为参考随后会有详细讲解
事实上 store 就是一个 javascript 对象而且,包含一个描述页面状态的数据 state。并且提供一些方法和行为。
- dispatch(action) 派发 action
- subscribe(listener) 订阅数据状态 state,当 state 状态发生了变化会调用者 listener 的回调函数来通知他们数据发改变了,需要更新界面。
- getState :
- replaceReducer(nextReducer)
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware)
// window.__REDUX_DEVTOOLS_EXTENSION__
));
action
对应用户操作(动作),本质是改变状态的信息。通常会包含动作类型(type),用于描述动作和与其他动作进行区分。还有就是数据(data)提供修改的数据。
const fetchPostsAction = {
type:FETCH_POSTS,
payload:[]
}
export const fetchPosts = ()=> dispatch => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res => res.json())
.then(posts => dispatch({
type:FETCH_POSTS,
payload:posts
}));
}
reducer
render 是将 action 的对状态改变动作映射,也就是实际落实到 store 的 state 上。reducer 是一个纯函数,也就是说明其没有侧边效应(副作用),而从保证状态的可预见性。
在 reducer 我们通过 type 对 action 进行分类
const initialState = {
items:[],
item:{}
}
export default function(state=initialState, action){
switch(action.type){
case FETCH_POSTS:
console.log('reducer')
return {
...state,
items:action.payload
}
break;
case NEW_POST:
break;
default:
return state;
}
}
我们先从官方文档出发实践一个小实例,
这里简单搭建一下,我们 webpack 作为项目构建工具,将 src 目录下 index.js 打包成为 bundle.js 放入到 dist 文件夹下供此文件夹下 index.html 引用。然后 live-server 启动一个服务就可以观察结果。
import { createStore } from 'redux';
function counter(state = 0,action){
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
let store = createStore(counter);
store.subscribe(() => console.log(store.getState()));
store.dispatch({ type: 'INCREMENT' })
// 1
store.dispatch({ type: 'INCREMENT' })
// 2
store.dispatch({ type: 'DECREMENT' })
可不可以自己写一个 Redux 的简单实现呢,Redux 背后就是发布订阅者模式,
redux-diagram
这里我用 Typescript 来写一个 Redux ,让大家可以了更好地理解 Redux 实现原理,其实任何复杂的框架都是从简单开始,从简单一步一步走向复杂。在走向复杂的道路上我们一路上让这种复杂更有规律,复杂程度在我们控制范围内,并且努力降低其复杂度。
interface Action {
type: string;
payload: any;
}
interface IGetState {
(): any;
}
interface ISubscribe {
(listener: Function): void;
}
interface IDispatch {
(action: Action): void;
}
interface IStore {
getState: IGetState;
subscribe: ISubscribe;
dispatch: IDispatch;
}
function createStore(reducer: any): IStore {
let state = {};
const getState = (): any => state;
const subscribe = (listener: Function): void => {};
const dispatch = (action: Action): void => {};
return {
getState,
subscribe,
dispatch
};
}
export default {
createStore
};
通过 typescript 接口我们定义了类型,有了类型可以对我们开发是一种约束和提示。这里createStore
就收一个 reducer 函数,然后返回一个 store 对象,store 提供对分发和订阅方法。 当状态 state 改变了时候,store 进行发布出该类型事件,对应于该事件类型的注册好的监听器会被触发执行回调函数来更新界面。
网友评论