blogs: mytheart的个人博客 掘金: mytheart
Languages and Tools:
🚅 前端技术博客,不定时更新
blogs: mytheart的个人博客 掘金: mytheart
Languages and Tools:
action reducer store
它是一个UI的解决方案,用于降低UI,以及UI关联的数据的复杂度。
传统的服务器端的MVC
环境:
以上的这种方式叫做服务端渲染,即服务器端将完整的页面组装好之后,一起发送给客户端。
服务器端需要处理UI中要用到的数据,并且要将数据嵌入到页面中,最终生成一个完整的HTML页面响应。
为了降低处理这个过程的复杂度,出现了MVC模式。
Controller: 处理请求,组装这次请求需要的数据
Model:需要用于UI渲染的数据模型
View:视图,用于将模型组装到界面中
前端MVC模式的困难
React解决了 数据 -> 视图 的问题
比如,上下文中有如下格式的数据:
value = {
users:[{},{},{}],
addUser: function(u){},
deleteUser: function(u){},
updateUser: function(u){}
}
Flux
Facebook提出的数据解决方案,它的最大历史意义,在于它引入了action的概念
action是一个普通的对象,用于描述要干什么。action是触发数据变化的唯一原因
store表示数据仓库,用于存储共享数据。还可以根据不同的action更改仓库中的数据
示例:
var loginAction = {
type: "login",
payload: {
loginId:"admin",
loginPwd:"123123"
}
}
var deleteAction = {
type: "delete",
payload: 1 // 用户id为1
}
Redux
在Flux基础上,引入了reducer的概念
reducer:处理器,用于根据action来处理数据,处理后的数据会被仓库重新保存。
export { default as createStore } from "./createStore"
export { default as bindActionCreators } from "./bindActionCreators"
export { default as combineReducers } from "./combineReducers"
export { default as applyMiddleware } from "./applyMiddleware"
export { default as compose } from "./compose"
/**
* 得到一个指定长度的随机字符串
* @param {*} length
*/
function getRandomString(length) {
return Math.random().toString(36).substr(2, length).split("").join(".")
}
export default {
INIT() {
return `@@redux/INIT${getRandomString(6)}`
},
UNKNOWN() {
return `@@redux/PROBE_UNKNOWN_ACTION${getRandomString(6)}`
}
}
/**
* 判断某个对象是否是一个plain-object
* @param {*} obj
*/
export default function isPlainObject(obj) {
if (typeof obj !== "object") {
return false;
}
return Object.getPrototypeOf(obj) === Object.prototype;
}
import ActionTypes from "./utils/ActionTypes"
import isPlainObject from "./utils/isPlainObject"
/**
* 实现createStore的功能
* @param {function} reducer reducer
* @param {any} defaultState 默认的状态值
*/
export default function createStore(reducer, defaultState, enhanced) {
//enhanced表示applymiddleware返回的函数
if (typeof defaultState === "function") {
//第二个参数是应用中间件的函数返回值
enhanced = defaultState;
defaultState = undefined;
}
if (typeof enhanced === "function") {
//进入applyMiddleWare的处理逻辑
return enhanced(createStore)(reducer, defaultState);
}
let currentReducer = reducer, //当前使用的reducer
currentState = defaultState; //当前仓库中的状态
const listeners = []; //记录所有的监听器(订阅者)
function dispatch(action) {
//验证action
if (!isPlainObject(action)) {
throw new TypeError("action must be a plain object");
}
//验证action的type属性是否存在
if (action.type === undefined) {
throw new TypeError("action must has a property of type");
}
currentState = currentReducer(currentState, action)
//运行所有的订阅者(监听器)
for (const listener of listeners) {
listener();
}
}
function getState() {
return currentState;
}
/**
* 添加一个监听器(订阅器)
*/
function subscribe(listener) {
listeners.push(listener); //将监听器加入到数组中
let isRemove = false;//是否已经移除掉了
return function () {
if (isRemove) {
return;
}
//将listener从数组中移除
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
isRemove = true;
}
}
//创建仓库时,需要分发一次初始的action
dispatch({
type: ActionTypes.INIT()
})
return {
dispatch,
getState,
subscribe
}
}
import isPlainObject from "./utils/isPlainObject"
import ActionTypes from "./utils/ActionTypes"
function validateReducers(reducers) {
if (typeof reducers !== "object") {
throw new TypeError("reducers must be an object");
}
if (!isPlainObject(reducers)) {
throw new TypeError("reducers must be a plain object");
}
//验证reducer的返回结果是不是undefined
for (const key in reducers) {
if (reducers.hasOwnProperty(key)) {
const reducer = reducers[key];//拿到reducer
//传递一个特殊的type值
let state = reducer(undefined, {
type: ActionTypes.INIT()
})
if (state === undefined) {
throw new TypeError("reducers must not return undefined");
}
state = reducer(undefined, {
type: ActionTypes.UNKNOWN()
})
if (state === undefined) {
throw new TypeError("reducers must not return undefined");
}
}
}
}
export default function (reducers) {
//1. 验证
validateReducers(reducers);
/**
* 返回的是一个reducer函数
*/
return function (state = {}, action) {
const newState = {}; //要返回的新的状态
for (const key in reducers) {
if (reducers.hasOwnProperty(key)) {
const reducer = reducers[key];
newState[key] = reducer(state[key], action);
}
}
return newState; //返回状态
}
}
export default function (actionCreators, dispatch) {
if (typeof actionCreators === "function") {
return getAutoDispatchActionCreator(actionCreators, dispatch);
}
else if (typeof actionCreators === "object") {
const result = {}; //返回结果
for (const key in actionCreators) {
if (actionCreators.hasOwnProperty(key)) {
const actionCreator = actionCreators[key]; //取出对应的属性值
if (typeof actionCreator === "function") {
result[key] = getAutoDispatchActionCreator(actionCreator, dispatch);
}
}
}
return result;
}
else {
throw new TypeError("actionCreators must be an object or function which means action creator")
}
}
/**
* 得到一个自动分发的action创建函数
*/
function getAutoDispatchActionCreator(actionCreator, dispatch) {
return function (...args) {
const action = actionCreator(...args)
dispatch(action);
}
}
export default function compose(...funcs) {
if (funcs.length === 0) {
return args => args; //如果没有要组合的函数,则返回的函数原封不动的返回参数
}
else if (funcs.length === 1) {
//要组合的函数只有一个
return funcs[0];
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
// return function (...args) {
// let lastReturn = null; //记录上一个函数返回的值,它将作为下一个函数的参数
// for (let i = funcs.length - 1; i >= 0; i--) {
// const func = funcs[i];
// if (i === funcs.length - 1) {//数组最后一项
// lastReturn = func(...args)
// }
// else {
// lastReturn = func(lastReturn)
// }
// }
// return lastReturn;
// }
}
import compose from "./compose"
/**
* 注册中间件
* @param {...any} middlewares 所有的中间件
*/
export default function (...middlewares) {
return function (createStore) { //给我创建仓库的函数
//下面的函数用于创建仓库
return function (reducer, defaultState) {
//创建仓库
const store = createStore(reducer, defaultState);
let dispatch = () => { throw new Error("目前还不能使用dispatch") };
const simpleStore = {
getState: store.getState,
dispatch: store.dispatch
}
//给dispatch赋值
//根据中间件数组,得到一个dispatch创建函数的数组
const dispatchProducers = middlewares.map(mid => mid(simpleStore));
dispatch = compose(...dispatchProducers)(store.dispatch);
return {
...store,
dispatch
}
}
}
}
一个函数组件中可以有多个状态,这种做法非常有利于横向切分关注点
useState原理
注意细节
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.