• redux原理


    Redux实现原理

    不同组件需要依赖同一个数据的时候,就需要状态提升至这些组件的根组件。
    redux是状态统一管理工具,需要使用它的原因是: 组件之间通信统一管理,方便代码维护。

    React中有一个特性context,只要某个组件使用context存储了数据,那么这个组件的所有子组件都可以访问该context内容,并且还可以修改它。就像是这个组件的全局变量,它的所有子组件都可以访问这个全局变量。
    如下图,假设要更改主题颜色,那么在Index根组件的context中存储当前主题色,那么它的子组件header,footer,title,menu都可以访问到,并且可以修改。

    Redux的统一数据管理,与React的关联之处利用的就是context特性
    但是context有一个缺点就是,所有的子组件都可以修改共享的内容,每个组件都能够改 context 里面的内容会导致程序的运行不可预料。所以React团队的做法就是,提高修改的门槛,修改数据时统一调用dispatch函数,并且需要传入修改类型,如果dispatch中不存在该类型,则不允许修改。
    接下来简单推理一下redux的实现过程(假设有组件Index,Header,Footer)。
    1、第一步是需要有一个存储数据的对象,定义为appState

       	var appState = {
    	   	themeColor:'red',
    	   	themeBackground:'black'
    	};
    	//还需要一个修改数据的函数
    	function dispatch(action){
    		switch(action.type){
    			case 'UPDATE_THEME_COLOR':
    				appState.themeColor = action.color;break;
    			case 'UPDATE_THEME_BACKGROUND':
    				appState.themeBackground = action.color;break;
    			default break;		
    		}
    	}
    	//修改完数据,就需要重新渲染了,定义渲染函数
    	function renderApp(state){
    		renderHeader(state);
    		renderFooter(state);
    	}
    	function renderHeader(state){
    		header = document.getElementById('header');
    		header.style.color = state.color;
    		header.style.backgroundColor = state.themeBackground;
    	}
    	function renderFooter(state){
    		title = document.getElementById('footer');
    		footer.style.color = state.color;
    		footer.style.backgroundColor = state.themeBackground;
    	}
    	
    	dispatch({type:'UPDATE_THEME_COLOR',color:'green'})//修改主题色
    	renderApp(appState)//执行重新渲染
    
    

    2、封装state和dispatch,命名为store,方便复用,同时添加监听,当数据变化时,通知订阅者重新渲染

    	function createStore(state,stateChanger){
    		const getState = () => state;//获取数据
    		const listeners = [];
    		const subscribe = (listener) => listeners.push(listener);
    		const dispatch = (action) => {
    			stateChanger(state, action);
    			listeners.forEach((listener)=>listener());
    		};
    		return {getState,dispatch,subscribe};
    	}
    	//实例化一个store。为了统一命名,dispatch改为stateChanger,appState改名为state
    	const store = createStore(state,stateChanger);
    	renderApp(store.getState());//首次渲染
    	store.subscribe(renderApp(store.getState()));//添加订阅者,监听到变化就重新渲染数据
    	store.dispatch({type:'UPDATE_THEME_COLOR',color:'green'});//修改主题
    

    3、第二步有一个很大的缺陷就是,每次修改数据就重新全部渲染一遍,对性能影响很大。
    优化点是: 判断数据是否有变化,如果没变化就不需要重新渲染,另外stateChanger与state合为一体。

    	//此处用到es6的浅复制,例如
    	let a = { name:'HAPPY',attr:{age:23},common:{sex:'女'}};
    	let b = {...a,attr:{age:24}};//b为{name:'HAPPY',attr:{age:24},common:{sex:'女'}} 
    	a.name===b.name//true
    	a.attr===b.attr//false
    	a.common===b.common//true
    	//这样有50%以上的复用率
    	function stateChanger(state,action){
    		if(!state){
    			 return {
    				 themeColor:'red',
    			   	 themeBackground:'black'
    			 }
    		}
    		const newState = {...state};
    		switch(action.type){
    			case 'UPDATE_THEME_COLOR':
    				return {
    					...newState,
    					themeColor: action.color
    				};
    			case 'UPDATE_THEME_BACKGROUND':
    				return {
    					...newState,
    					themeBackground: action.color
    				};
    			default 
    				return newState;	
    		}
    	}
    	//那么渲染的时候需要知道oldState和newState,这样才能对比数据的变化
    	function renderApp(state,oldState={}){//此处oldState放在后面,并且给默认值,是为了兼容首次渲染,首次渲染olsState是没有值的,所以给默认值
    		if(oldState===state){
    			return;
    		}
    		renderHeader(oldState,state);
    		renderFooter(oldState,state);
    	}
    	//如果renderHeder需要的渲染的数据是state内的子对象,那么在renderHeader渲染之前,也需要判断一下数据是否有变化,此处举的例子state结构简单,所以不需要判断。
    	
    	function createStore(stateChanger){//此处是优化state与stateChanger结合。
    		let state = null
    		const getState = () => state;//获取数据
    		const listeners = [];
    		const subscribe = (listener) => listeners.push(listener);
    		const dispatch = (action) => {
    			state = stateChanger(state, action);
    			listeners.forEach((listener)=>listener());
    		};
                    dispatch({});//初始化,获取state
    		return {getState,dispatch,subscribe};
    	}
    	//最后需要oldState,那么我们就需要定义oldState
    	const store = createStore(stateStranger);
    	const oldState = store.getState();
    	store.subscribe(()=>{
    		const newState = store.getState();
    		renderApp(oldState,newState);
    		oldState = newState;
    	});//添加监听
    	renderApp(store.getState())//首次渲染
    	store.dispatch({type:'UPDATE_THEME_COLOR',color:'green'});//修改主题
    

    4.此时的stateChanger是一个纯函数,就是内部逻辑只与参数有关,并且无副作用(也就是对其他数据没有任何影响)。它要做的仅仅是 —— 初始化和计算新的 state。(并不会修改state,因为我们每次返回的都是新的对象)
    而这个函数就是redux中的reducer,那么我们给stateChanger改名字为reducer.现在我们的redux就实现完成了。

    	 function reducer(state,action){...}
    	 function createStore(reducer){...}
    	 //接下来我们就可以定义不同的reducer,生成不同的store了,并且修改监听,例如
    	 function themeReducer(state,action){...}
    	 const store = createStore(themeReducer);
    	 // 监听数据变化重新渲染页面
    	 store.subscribe(() => renderApp(store.getState()))
    	 // 首次渲染页面
    	 renderApp(store.getState())
    	 // 后面可以随意 dispatch 了,页面自动更新
    	 store.dispatch(...)
    
    但是我们怎么跟react进行连接呢?怎么把redux用在react中呢?就需要react-redux来连接。下一篇继续

    参考教程:(http://huziketang.mangojuice.top/books/react)

  • 相关阅读:
    《Java并发编程实战》(五)---- 任务执行
    《Java并发编程实践》(四)---- 构建阻塞
    《Java并发编程实践》(三)---- 组合对象
    《Java8实战》(三)---- 重构测试和调试
    《Java核心技术》---- 多线程
    《Java并发编程实战》(二)---- 对象的共享
    《Java 8 实战》(三)---- 流
    《Java 8 实战》(二)—— Lambda
    《Java 8 实战》(一)——通过行为参数化传递代码
    Android_问卷调查
  • 原文地址:https://www.cnblogs.com/HappyYawen/p/9071238.html
Copyright © 2020-2023  润新知