理解Redux的设计思想

理解Redux的设计思想、原理;

前言: 你能点开并且来到这篇文章,说明你用过redux,并且希望尽可能深入了解下redux内部运行机制与原理,这将是本文重点探讨的内容。

开始前说明: redux是一个独立的库,用于项目内公共状态管理的库,与其他第三方框架(库)无直接关联,可与其他框架搭配使用,也可独立使用 !Tip:为什么强调这一点?因为怕有些同学直接从react-redux开始接触到的redux,难免会产生误区,是不是必须要和react一起使用?答案是:“不需要”;官网上找到的这句话就是答案: Redux can be used as a data store for any UI layer. The most common usage is with React and React Native, but there are bindings available for Angular, Angular 2, Vue, Mithril, and more. Redux simply provides a subscription mechanism which can be used by any other code. That said, it is most useful when combined with a declarative view implementation that can infer the UI updates from the state changes, such as React or one of the similar libraries available.

废话不多说立刻马上进入主题
一、先独立使用redux,看看redux给我们带来了什么:

const redux = require('redux');

const initialState = {
  count: 0
}
// reducer
function reducer(state = initialState, action) {
  switch (action.type) {
    case "ADD_COUNT":
      return { ...state, counter: action.num }
    default:
      return state;
  }
}
const store = redux.createStore(reducer)
// 订阅store的修改
store.subscribe(() => {
  console.log("count:", store.getState().counter);
})

// actions
const action1 = { type: "ADD_COUNT", num: 1 };
// 派发action
store.dispatch(action1);

以上是最基本的redux的使用方式,首先创建一个store,给store传入reducer,store给我们暴露三个接口getState、getState、subscribe,通过getState可拿到state,通过dispatch可修改state,通过subscribe可订阅state的变化;

二、深入理解redux的设计思想,一步步揭开createStore、getState、dispatch、subscribe的面纱:
为什么要有dispatch?抽象一点理解:项目里有很多的组件,很多地方都需要用到count这个状态,那么他们谁也都可以修改这个状态,某天当state变了的时候你不一定知道是谁改的,那么我们需要有一个“管理员”来帮我们管理这些的状态,这时候引入了reducer函数,专门负责修改数据,哪个组件需要改都得经过它。

function reducer(state, action) {
  switch (action.type) {
    case "CHANGE_COUNT":
      state.count = action.num;
      break;
    default:
      return state;
  }
}

为什么要有createStore?抽象理解:我们有了状态state,又有了dispatch,这时候我们需要一个高层管理者store,帮我们管理好他们,所以我们就有了createStore这个函数帮我们生成store, 这样在用的时候就可以直接store.getState, store.dispatch的方式获取和更改组件状态。

function createStore(state, reducer) {		//需要传入state,这是为了我们方便理解,
											//自己写的函数哦
  const getState = () => state;	
  const dispatch = (action) => {
  	reducer(state, action);
  }
  return { getState, dispatch }
}

(一)于是,我们暂且可以这样使用:

let initState = { count: 666 };

function reducer(state, action) {
  switch (action.type) {
    case "CHANGE_COUNT":
      state.count = action.num;
      break;
    default:
      return state;
  }
}

function createStore(state, stateChanger) {
  const getState = () => state;
  const dispatch = (action) => {
  	reducer(state, action);
  }
  return { getState, dispatch }
}

const store = createStore(initState, reducer); 
//这样我们就明白了store里面有什么,  有getState和dispatch

renderApp(store.getState());
//renderApp为伪代码,我们暂且把它理解为页面render函数,用来首次渲染页面;

store.dispatch({ type: 'CHANGE_COUNT', num: '999' }); // 修改count

// 注意:这里修改完后需要我们手动重新render
renderApp(store.getState()); 						 // 把新的数据渲染到页面上

(二) 到这里我们会发现,我们目前只是实现了单独的获取状态与修改状态,但状态改变了我组件并没办法也随着改变,需要手动再getState()一次获取状态后,再手动render。于是,这时候就需要观察者模式,我们需要订阅store数据的改变,然后自动调用renderApp。我们重新改造createStore

function createStore(state, reducer) {
  const getState = () => state;
  const listeners = [];
  // 订阅函数
  const subscribe = (listener) => {
    listeners.push(listener)} 
  const dispatch = (action) => {
    reducer(state, action);
    // 数据已发生改变就把所有的listener调用一遍
    listeners.forEach(listener => {
      listener();
    })
  }

  return { getState, dispatch, subscribe }
}

(三)于是,createStore的功能变得强大了,我们可以这样使用:

let initState = { count: 666 }

function reducer(state, action) {
  switch (action.type) {
    case "CHANGE_COUNT":
      state.count = action.num;
      break;
    default:
      return state;
  }
}

function createStore(state, reducer) {
  const getState = () => state;
  const listeners = [];
  // 订阅函数
  const subscribe = (listener) => {
    listeners.push(listener)} 
  const dispatch = (action) => {
    reducer(state, action);
    // 数据已发生改变就把所有的listener调用一遍
    listeners.forEach(listener => {
      listener();
    })
  }
  return { getState, dispatch, subscribe }
}

const store = createStore(initState, reducer); 

store.subscribe(() => renderApp(store.getState()));
// 监听数据变化,每次数据改变都会自动执行renderApp

renderApp(store.getState());
//首次渲染页面;

store.dispatch({ type: 'CHANGE_COUNT', num: '999' }); // 修改count
/* 这时,我们再次修改state时,便又会执行dispatch函数,
   但与上次不同的是这次执行dispatch的时候同时也会遍历listeners,执行每个listener,
   listener是什么?是我们通过subscribe传入的渲染函数呀,这个函数又被执行一次说明什么?
   岂不是做到了数据订阅,状态改变组件自动渲染了,不再需要我们手动操作再次渲染;
*/

(四)到这里,我们思考一个问题,如果我们dispatch({ type: 'CHANGE_COUNT', num: '666' }),这时count的值和之前一样。此时组件会被重复渲染吗?答案是:会!那么这样就会带来严重的性能问题。于是,reducer对我们提出了一个要求,reducer必须是一个纯函数,reducer要对前后产生的state进行一个对比,每次修改完state后返回一个新的object,这样就能够通过对比前后的state是否相等,来决定是否renderApp,于是我们再次改造reducer就有了下面这种用法:

let initState = { count: 666 }
function reducer(state = initState, action) {		// 请注意这里的变化
 
  switch (action.type) {
    case "CHANGE_COUNT":
      return {...state, count: action.count}
      break;
    default:
      return state;
  }
}

function createStore(reducer) {
  let state = undefined;                                 // 请注意这里的变化
  const getState = () => state;
  const listeners = [];
  // 订阅函数
  const subscribe = (listener) => {
    listeners.push(listener)} 
  const dispatch = (action) => {
    state = reducer(state, action);				  // 请注意这里的变化
    /* 覆盖原先的state,可以看到:由于reducer返回的是一个新的object,那在外层,
       我们就可以通过对比nextProps跟this.props 来决定是否重新渲染 */
    listeners.forEach(listener => {
      listener();
    })
  }
  dispatch({});									 // 请注意这里的变化
  /* 这一步骤表示初始化 state,此时state为undefined,没有值,
  reducer会取initState作为初始state */
  return { getState, dispatch, subscribe }
}

const store = createStore(reducer); 
// 这里我们也按照官方的用法只传入reducer,这里并未传入initState;

store.subscribe(() => renderApp(store.getState())) 
// 监听数据变化,每次数据改变都会自动执行renderApp

renderApp(store.getState());
// 首次渲染页面;

store.dispatch({ type: 'CHANGE_COUNT', num: '999' }) // 修改count

到这里为止,我们自己所写的createStore、getState、dispatch、subscribe所有用法基本和官方一致,由此便明白了redux的设计思路与思想;

总结:我们整个过程就是不断地发现问题,解决问题;
1、共享状态 -> dispatch
2、store统一管理 -> dispatch, getState
3、性能优化 --> reducer是一个纯函数
4、最终初始化整个reducer

Tip:本文也是参考了某平台某位博主的思路分析,才最终得此文章!
有收获的话就点赞收藏😘💐

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值