redux 实现原理是什么?能解决那些问题
随着 JavaScript 单页应用开发日趋势复杂,管理不断变化的state 很是困难
Redux的出现解决了state 数据问题。
这里我用一个最近比较火的电视剧 《安家》来简单作一个demo。来为你们介绍一下
故事开始拉!
首先 有一个客户到安家天下房屋中介找房子 ,那这里有一个先决条件中介和客户。
1、 咱们先建立一个场景 创建一个文件夹app 并建立一个index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Redux的实现原理</title>
</head>
<body>
<!-- 找房子的用户 -->
<div id='user_name'></div>
<div id='user_data'></div>
<!-- 安家天下房屋中介 -->
<div id='intermediaary'></div>
<div id='inter_data' ></div id='inter_data'>
<!-- 故事脚本-->
<script src="app.js"></script>
</body>
</html>复制代码
2、 接下来建立咱们故事的脚步 app.js
//一、初始化数据 定义好角色 张三来安家找找房子
let appStore = {
user: { name: "张三", data: "找房子" },
intermediaary: { name: "安家天下", data: "房四井接待办理找房子" }
};
//输出用户的需求
function renderUser(user) {
let element = document.querySelector("#user_name");
element.innerHTML = user.name; //用户张三须要找房子
let ev = document.querySelector("#user_data");
ev.innerHTML = user.data;
}
//中介处理的需求
function renderInermediaay(intermediaary) {
let element = document.querySelector("#intermediaary");
element.innerHTML = intermediaary.name;
let ev = document.querySelector("#inter_data");
ev.innerHTML = intermediaary.data; //安家天下房四井
}
//定义函数 而且把内容输出
function renderApp(appStore) {
renderUser(appStore.user);
renderInermediaay(appStore.intermediaary);
}
renderApp(appStore); //执行脚本复制代码
张三找房子 安家天下方四井开始接待了,那这里有什么问题呢?
状态是一个全局变量 ,安全性低 任何地方均可以改 ?增长修改的门槛不能随便改。
这时候咱们须要一个action 建立一个dispatch函数
3、 这里咱们先定义好房屋中介能作到的常量
//定义好房子中介和用户之间都懂的事
const UPDATE_USER_NAME = "UPDATE_USER_NAME"; //用户的名字
const UPDATE_USER_DATA = "UPDATE_USER_DATA"; //用户要作什么事情
const UPDATE_INTERMEDIAARY_NAME = "UPDATE_INTERMEDIAARY_NAME"; //中介的名字
const UPDATE_INTERMEDIAARY_DATA = "UPDATE_CONTEN_TEXT"; //中介能接待的事情
//action 派发分发动做 描述你想作什么? 是一个普通的属性 必须有一个type
function dispatch(action) {
switch (action.type) {
case UPDATE_USER_NAME:
appStore.user.name = action.name;
break;
case UPDATE_USER_DATA:
appStore.user.data = action.data;
break;
case UPDATE_INTERMEDIAARY_NAME:
appStore.intermediaary.name = action.name;
break;
case UPDATE_INTERMEDIAARY_DATA:
appStore.intermediaary.data = action.data;
break;
default:
throw new Error("臣妾作不到啊!");
}
}
//李四来安家卖房子了
setTimeout(() => {
dispatch({ type: UPDATE_USER_NAME, name: "李四" });
dispatch({ type: UPDATE_USER_DATA, data: "来卖房子了" });
dispatch({ type: UPDATE_INTERMEDIAARY_DATA, data: "王子接待买房子业务" });
renderApp(appStore); //执行脚本
}, 1000);复制代码
4、 这里能保证访问中介只能作这四个事情 其余一律不处理 增量一点安全想可是没有解决appStore 全局变量的问题。
因此咱们建立一个 函数把appStore 放进去 createStore
一、把全局变量放进 createStore 中
二、dispatch也放进去 并建立获取当前state functon
// 添加函数仓库
function createStore() {
//一、初始化数据 定义好角色 张三来安家找找房子
let state = {
user: { name: "张三", data: "找房子" },
intermediaary: { name: "安家天下", data: "房四井接待办理找房子" }
};
// 建立一个获取当前state的方法
function getState() {
return JSON.parse(JSON.stringify(state)); //深拷贝一下
}
//action 派发分发动做 描述你想作什么? 是一个普通的属性 必须有一个type
function dispatch(action) {
switch (action.type) {
case UPDATE_USER_NAME:
state.user.name = action.name;
break;
case UPDATE_USER_DATA:
state.user.data = action.data;
break;
case UPDATE_INTERMEDIAARY_NAME:
state.intermediaary.name = action.name;
break;
case UPDATE_INTERMEDIAARY_DATA:
state.intermediaary.data = action.data;
break;
default:
throw new Error("臣妾作不到啊!");
}
}
return { getState, dispatch };
}复制代码
这样解决了全局变量不可控问题。
5、 新问题来了每一个应用处理逻辑不一样 咱们不能把 dispatch 直接放在createStore 下 不然 咱们须要创建多个 状态管理,这个是没有必要的因此这里须要进一步优化添加一个处理函数也就是咱们的reducer.并添加用户的初始化状态.
// 添加函数仓库
function createStore(reducer) {
//一、初始化数据 定义好角色 张三来安家找找房子
let state; //第一次动做是空对象没有
// 建立一个获取当前state的方法
function getState() {
return JSON.parse(JSON.stringify(state)); //深拷贝一下
}
//action 派发分发动做 描述你想作什么? 是一个普通的属性 必须有一个type
function dispatch(action) {
state = reducer(state, action);
}
dispatch({}); //获取初始化状态
return { getState, dispatch };
}
//添加用户初始化状态
let initState = {
user: { name: "张三", data: "找房子" },
intermediaary: { name: "安家天下", data: "房四井接待办理找房子" }
};
//添加处理器 :根据老的状态处理返回新的状态
let reducer = function(oldState = initState, action) {
switch (action.type) {
case UPDATE_USER_NAME:
//这里须要注意必定要返回一个新的对象
return { ...oldState, user: { ...oldState.data, name: action.name } };
// break;
case UPDATE_USER_DATA:
return { ...oldState, user: { ...oldState.user, data: action.data } };
case UPDATE_INTERMEDIAARY_NAME:
return {
...oldState,
intermediaary: { ...oldState.intermediaary, name: action.name }
};
case UPDATE_INTERMEDIAARY_DATA:
return {
...oldState,
intermediaary: { ...oldState.intermediaary, data: action.data }
};
default:
// throw new Error("臣妾作不到啊!");
return oldState; //返回老的状态
}
};
let store = createStore(reducer);
renderApp(store.getState());
//李四来安家卖房子了
setTimeout(() => {
store.dispatch({ type: UPDATE_USER_NAME, name: "李四" });
store.dispatch({ type: UPDATE_USER_DATA, data: "来卖房子了" });
store.dispatch({
type: UPDATE_INTERMEDIAARY_DATA,
data: "王子接待买房子业务"
});
// console.log(store.getState());
renderApp(store.getState());
}, 1000);复制代码
解决了在各类环境使用问题 接下来 看看还有哪些问题?
没错 就是 renderApp 目前咱们的程序每次都须要本身渲染 手动去调用很不方便,
六 、添加发布订阅 让咱们的状态自动刷新 修改createStore
//输出用户的需求
function renderUser(user) {
let element = document.querySelector("#user_name");
element.innerHTML = user.name; //用户张三须要找房子
let ev = document.querySelector("#user_data");
ev.innerHTML = user.data;
}
//中介处理的需求
function renderInermediaay(intermediaary) {
let element = document.querySelector("#intermediaary");
element.innerHTML = intermediaary.name;
let ev = document.querySelector("#inter_data");
ev.innerHTML = intermediaary.data; //安家天下房四井
}
//定义好房子中介和用户之间都懂的事
const UPDATE_USER_NAME = "UPDATE_USER_NAME"; //用户的名字
const UPDATE_USER_DATA = "UPDATE_USER_DATA"; //用户要作什么事情
const UPDATE_INTERMEDIAARY_NAME = "UPDATE_INTERMEDIAARY_NAME"; //中介的名字
const UPDATE_INTERMEDIAARY_DATA = "UPDATE_CONTEN_TEXT"; //中介能接待的事情
// 添加函数仓库
function createStore(reducer) {
let listeners = []; //存储全部状态
let state; //第一次动做是空对象没有
// 建立一个获取当前state的方法
function getState() {
return JSON.parse(JSON.stringify(state)); //深拷贝一下
}
//action 派发分发动做 描述你想作什么? 是一个普通的属性 必须有一个type
function dispatch(action) {
state = reducer(state, action);
listeners.forEach(fn => fn());
}
dispatch({}); //获取初始化状态
//添加订阅模式 ,供外部订阅本仓库中的状态的变化 ,若是状态变化发生了改变就执行该程序
function subscribe(listener) {
listeners.push(listener); //添加订阅
//取消 已发布订阅
return function() {
listeners = listeners.filter(item => {
//过滤数组
listener != item;
});
};
}
return { getState, dispatch, subscribe };
}
//添加用户初始化状态
let initState = {
user: { name: "张三", data: "找房子" },
intermediaary: { name: "安家天下", data: "房四井接待办理找房子" }
};
//添加处理器 :根据老的状态处理返回新的状态
let reducer = function(oldState = initState, action) {
switch (action.type) {
case UPDATE_USER_NAME:
console.log({
...oldState,
user: { ...oldState.user, data: action.data }
});
return { ...oldState, user: { ...oldState.data, name: action.name } };
case UPDATE_USER_DATA:
// state.user.data = action.data;
// break;
return { ...oldState, user: { ...oldState.user, data: action.data } };
case UPDATE_INTERMEDIAARY_NAME:
return {
...oldState,
intermediaary: { ...oldState.intermediaary, name: action.name }
};
case UPDATE_INTERMEDIAARY_DATA:
return {
...oldState,
intermediaary: { ...oldState.intermediaary, data: action.data }
};
default:
// throw new Error("臣妾作不到啊!");
return oldState; //返回老的状态
}
};
let store = createStore(reducer);
//定义函数 而且把内容输出
function renderApp() {
renderUser(store.getState().user);
renderInermediaay(store.getState().intermediaary);
}
renderApp();
//添加订阅
store.subscribe(renderApp);
//李四来安家卖房子了
setTimeout(() => {
store.dispatch({ type: UPDATE_USER_NAME, name: "李四" });
store.dispatch({ type: UPDATE_USER_DATA, data: "来卖房子了" });
//注意 用户没有更换安家天下中介 😁
store.dispatch({
type: UPDATE_INTERMEDIAARY_DATA,
data: "王子接待买房子业务"
});
}, 1000);复制代码
好了咱们的客户能够任意的到咱们的房屋中介来办理买卖房屋业务了 是否是很简单 。