JavaScript   发布时间:2022-04-16  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了浅谈redux以及react-redux简单实现大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

写在前头@H_489_2@

随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态)。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。

管理不断变化的 state 非常困难。如果一个 model 的变化会引起另一个 model 变化,那么当 view 变化时,就可能引起对应 model 以及另一个 model 的变化,依次地,可能会引起另一个 view 的变化。直至你搞不清楚到底发生了什么。state 在什么时候,由于什么原因,如何变化已然不受控制。 当系统变得错综复杂的时候,想重现问题或者添加新功能就会变得举步维艰。

如果这还不够糟糕,虑一些来自前端开发领域的新需求,如更新调优、服务端渲染、路由跳转前请求数据等等。前端开发者正在经受前所未有的复杂性,难道就这么放弃了吗?当然不是。

这里的复杂性很大程度上来自于:我们总是将两个难以理清的概念混淆在一起:变化和异步。 如果把二者分开,能做的很好,但混到一起,就变得一团糟。一些库如 React 试图在视图层禁止异步和直接操作 DOM 来解决这个问题。美中不足的是,React 依旧把处理 state 中数据的问题留给了我们自己。而 redux 就可以来帮我管理这些状态;

浅谈redux以及react-redux简单实现

s.js ├── .gitignore ├── package.json ├── package-lock.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json ├── README.md └── src ├── App.js ├── Demo │ ├── actionCreate.js │ ├── Demo.jsx │ ├── react-redux.js │ ├── reducer.js │ ├── redux.js │ ├── style.css │ └── thunk.js └── index.js

一、 redux API createStore 的实现@H_489_2@

首先我们先结合 reducer 以及 action 的知识简单实现开头展示的 demo,并逐步揭晓 createStore 的神秘面纱;

1.1 准备工作:@H_489_2@

{ switch(action.typE){ case '@R_675_9004@updatE': return {...state,...action.payloaD}; case 'AGE_GROW': return {...state,age: state.age + 1}; case 'SEX_updatE': return {...state,...action.payloaD}; default: return state; } }
{ return { payload:{user},type: '@R_675_9004@updatE',}; }

export const changeAge = () => {@H_618_35@ return { type: 'AGE_GROW' };@H_618_35@ }

.btn{ height: 31px;

}@H_618_35@ .input{@H_618_35@ height: 25px;@H_618_35@ }

export default class Demo extends React.Component{@H_618_35@ onChange = () => {}@H_618_35@ onClick = () => {}@H_618_35@ render(){@H_618_35@ return (

user: xxx,age: xxx

user:
); } }

浅谈redux以及react-redux简单实现

1.2 demo 的初次实现代码@H_489_2@

  • 创建全局状态 state;
  • 创建监听队列;
  • 针对监听队列,新增函数用于将指定监听对象添加到队列中;
  • 在函数 dispatch 中执行 reducer 将返回值作为新的 state,同时依次执行监听对象;
  • 默认执行一次 dispatch 给定一个 type 相对唯一的 action, 目的是为了匹配 reducer 的默认状态值,从而实现对 redux state 的初始化;
  • 在组件 Demo 通过在函数 update 使用 this.setState 将全局 state 保存到 react state 中,并将函数 update 添加到监听队列中;从而使得当我们一旦试图通过 dispatch 修改全局状态时,能够及时更新 react state 最终触发 react 生命周期 render;
  • 在 react 生命周期 componentDidMount 中我们除了将 update 添加到监听队列以外,还需手动执行一次 update 其主要目的就是为了首次初始化 react state;
{ changeAge,changeUser } from './actionCreate'; import { reducer } from './reducer'; import './style.css';

let state;@H_618_35@ const listeners = [];@H_618_35@ const subscribe = (listener) => {@H_618_35@ listeners.push(listener);@H_618_35@ }@H_618_35@ const dispatch = (action) => {@H_618_35@ state = reducer(state,action);@H_618_35@ console.log(statE);@H_618_35@ listeners.forEach(v => v());@H_618_35@ }@H_618_35@ dispatch({type: '%$&HJKAJJHDJHJ'});

export default class Demo extends React.Component{@H_618_35@ state = {user: 'xxx',age: 'xxx'};@H_618_35@ componentDidMount(){@H_618_35@ subscribe(this.updatE);@H_618_35@ this.update();@H_618_35@ }

update = () => {@H_618_35@ this.setState(statE);@H_618_35@ }

onChange = (E) => {@H_618_35@ dispatch(changeUser(e.target.value));@H_618_35@ }

onClick = () => {@H_618_35@ dispatch(changeAge());@H_618_35@ }

render(){@H_618_35@ return (

user: {this.state.user},age: {this.state.agE}

user:
); } }

1.3 API createStore 的实现@H_489_2@

其实上文的代码中对于 createStore 的实现原理已经基本描述清除,下面我们只是单纯的对代码进行了简单的封装;当然为了能够获取到 state 我们专门增加了一个函数 getState 来实现它;

export const createStore = (reducer) => {@H_618_35@ // 声明常量@H_618_35@ let state;@H_618_35@ const listeners = [];

// 获取状态@H_618_35@ const getState = () => {@H_618_35@ return state;@H_618_35@ }

// 添加监听对象@H_618_35@ const subscribe = (listener) => {@H_618_35@ listeners.push(listener);@H_618_35@ }

// [1]执行reducer修改状态 [2]遍历执行监听对象@H_618_35@ const dispatch = (action) => {@H_618_35@ state = reducer(state,action);@H_618_35@ listeners.forEach(v => v());@H_618_35@ }

// 初始化 state@H_618_35@ dispatch({type: '%$&HJKAJJHDJHJ'});

// 暴露接口@H_618_35@ return {getState,subscribe,dispatch};@H_618_35@ }

{ changeAge,changeUser } from './actionCreate'; import { reducer } from './reducer'; import { createStore } from './redux';

const store = createStore(reducer);

export default class Demo extends React.Component{@H_618_35@ state = {user: 'xxx',age: 'xxx'};@H_618_35@ componentDidMount(){@H_618_35@ store.subscribe(this.updatE);@H_618_35@ this.update();@H_618_35@ }

update = () => {@H_618_35@ this.setState(store.getState());@H_618_35@ }

onChange = (E) => {@H_618_35@ store.dispatch(changeUser(e.target.value));@H_618_35@ }

onClick = () => {@H_618_35@ store.dispatch(changeAge());@H_618_35@ }

render(){@H_618_35@ return (

user: {this.state.user},age: {this.state.agE}

user:
); } }

二、 react-redux API Provider 的实现@H_489_2@

在 react 中大多数情况下我们需要将状态传递给后代组件进行使用的,当然通过 props 是可以实现状态从父级到子级的传递,但是当状态需要传递的层级比较深的情况下再使用 props 就显得无力了,那么在 react-redux 中它是如何实现对 store 的传递的呢?

2.1 react context 的引入@H_489_2@

{ Component } from 'react'; import propTypes from 'prop-types'; import { createStore } from './Demo/redux'; import { reducer } from './Demo/reducer'; import Demo from './Demo/Demo';

// 创建 store@H_618_35@ const store = createStore(reducer);

class App extends Component {@H_618_35@ // 声明 childContextTypes 状态属性类型@H_618_35@ static childContextTypes = {@H_618_35@ store: propTypes.object@H_618_35@ };@H_618_35@ // 设置 childContext@H_618_35@ getChildContext(){@H_618_35@ return {storE}@H_618_35@ }@H_618_35@ render() {@H_618_35@ return ;@H_618_35@ }@H_618_35@ }@H_618_35@ export default App;

{ changeAge,changeUser } from './actionCreate';

export default class Demo extends React.Component{@H_618_35@ // 设置 context 状态值类型@H_618_35@ static contextTypes = {@H_618_35@ store: propTypes.object@H_618_35@ };

constructor(props,context){@H_618_35@ super(props,context);@H_618_35@ // 获取store@H_618_35@ this.store = context.store;@H_618_35@ this.state = {user: 'xxx',age: 'xxx'};@H_618_35@ }

componentDidMount(){@H_618_35@ this.store.subscribe(this.updatE);@H_618_35@ this.update();@H_618_35@ }

update = () => {@H_618_35@ this.setState(this.store.getState());@H_618_35@ }

onChange = (E) => {@H_618_35@ this.store.dispatch(changeUser(e.target.value));@H_618_35@ }

onClick = () => {@H_618_35@ this.store.dispatch(changeAge());@H_618_35@ }

render(){@H_618_35@ return (

user: {this.state.user},age: {this.state.agE}

user:
); } }

2.2 封装代码实现 Provider@H_489_2@

通过 react context 我们实现了对 store 的传递,到这里 Provider 的功能以及实现原理基本上应该算是清晰了,无非就是对组件进行包裹同时通过 react context 来传递共享 store;那么接下来我们通过对代码的封装来实现 Provider 组件;

export class Provider extends React.Component{@H_618_35@ // 设置 childContext 状态值类型@H_618_35@ static childContextTypes = {@H_618_35@ store: propTypes.object@H_618_35@ };

// 设置 childContext@H_618_35@ getChildContext(){@H_618_35@ return {store: this.props.storE}@H_618_35@ }

render(){@H_618_35@ return this.props.children;@H_618_35@ }@H_618_35@ }

{ Component } from 'react'; import { createStore } from './Demo/redux'; import { Provider } from './Demo/react-redux'; import { reducer } from './Demo/reducer'; import Demo from './Demo/Demo';

// 创建 store@H_618_35@ const store = createStore(reducer);

class App extends Component {@H_618_35@ render() {@H_618_35@ // 调用接口 Provider@H_618_35@ return ;@H_618_35@ }@H_618_35@ }@H_618_35@ export default App;

三、 react-redux API connect 高阶组件的实现@H_489_2@

上文中在后代组件如果需要获取 store 则需要手动通过获取 react context 来调用 store 并且需要显性的调用 store 内部的方法来进行一些操作;接下来我们来实现这么一个高阶组件 connect,我们只需要提供所需的 redux state 以及 action 创建函数,即可通过 props 获取到相应的 redux state,并且允许直接通过 props 调用action 创建函数来试图修改 redux state ;

(Component) => { return class NewComponent extends React.Component{ render(){ return } } }
(Component) => { return class NewComponent extends React.Component{ // 设置 context 状态值类型 static contextType = { store: propTypes.object }; // [1]获取 store [2]设置空 react state constructor(props,context){ super(props,context); this.store = context.store; this.state = {}; } render(){ return } } }
(Component) => { return class NewComponent extends React.Component{ static contextType = { store: propTypes.object }; constructor(props,context); this.store = context.store; this.state = {}; } // [1]添加监听对象 [2]手动执行监听对象,初始化 react state componentDidMount(){ this.store.subscribe(this.updatE); this.update(); }

update = () => {@H_618_35@ // 获取全部redux state 并添加到 react state@H_618_35@ const state = this.store.getState();@H_618_35@ this.setState(statE);@H_618_35@ }@H_618_35@ render(){@H_618_35@ // 通过 props 将 react state 全部传给子组件@H_618_35@ return <Component {...this.statE} />@H_618_35@ }@H_618_35@ }@H_618_35@ }

const connect = (mapStateToProps,context); this.store = context.store; this.state = {}; } componentDidMount(){ this.store.subscribe(this.updatE); this.update(); }

update = () => {@H_618_35@ // 执行 mapStateToProps 只获取用户指定需求的 state@H_618_35@ const state = this.store.getState();@H_618_35@ const filterState = mapStateToProps(statE);@H_618_35@ this.setState(filterStatE);@H_618_35@ }@H_618_35@ render(){@H_618_35@ return <Component {...this.statE} />@H_618_35@ }@H_618_35@ }@H_618_35@ }

(Component) => { return class NewComponent extends React.Component{ static contextTypes = { store: propTypes.object }; constructor(props,context); this.store = context.store; this.state = {}; } componentDidMount(){ this.store.subscribe(this.updatE); this.update(); }

update = () => {@H_618_35@ // 处理 state ===> 获取用户指定的 state@H_618_35@ const state = this.store.getState();@H_618_35@ const filterState = mapStateToProps(statE);

// 使用 dispatch 对 mapDispatchToProps 中的 action 创建函数进行包裹后返回@H_618_35@ const actionFun = {};@H_618_35@ for(let key in mapDispatchToProps){@H_618_35@ actionFun[key] = (...args) => {@H_618_35@ this.store.dispatch(mapDispatchToPropskey);@H_618_35@ }@H_618_35@ }@H_618_35@ // 一种简写方式: 骚操作@H_618_35@ // const actionFun = Object.keys(mapDispatchToProps)@H_618_35@ // .reduce((@R_764_10586@l,item) => {@H_618_35@ // return { ...@R_764_10586@l,[item]: (...args) => {dispatch(mapDispatchToPropsitem);}@H_618_35@ // } },{});

this.setState({...filterState,...actionFun});@H_618_35@ }@H_618_35@ render(){@H_618_35@ return <Component {...this.statE} />@H_618_35@ }@H_618_35@ }@H_618_35@ }

{ changeAge,changeUser } from './actionCreate'; import { connect } from './react-redux'; import './style.css';

// 编写 mapStateToProps 参数 redux state 返回所需的 redux state@H_618_35@ const mapStateToProps = (statE) => {@H_618_35@ return {user: state.user,age: state.agE};@H_618_35@ }

// 调用高阶组件@H_618_35@ @connect(mapStateToProps,{ChangeAge,changeUser})@H_618_35@ export default class Demo extends React.Component{@H_618_35@ onChange = (E) => {@H_618_35@ this.props.changeUser(e.target.value);@H_618_35@ }@H_618_35@ onClick = () => {@H_618_35@ this.props.changeAge();@H_618_35@ }@H_618_35@ render(){@H_618_35@ return (

user: {this.propS.User},age: {this.props.agE}

user:
); } }

四、redux API bindactioncreators 的实现@H_489_2@

在上文我们对 mapDispatchToProps 的处理过程就是 API bindactioncreators 的功能: 将给定 action 创建函数使用 dispatch 进行包裹后返回;

{ const actionFun = {}; // 遍历 mapDispatchToProps 中每个 action 创建函数 并使用 dispatch 包裹后返回 for(let key in mapDispatchToProps){ actionFun[key] = (...args) => { dispatch(mapDispatchToProps[key](...args)); } }

return actionFun;@H_618_35@ // 一种简写方式: 骚操作@H_618_35@ // return actionFun = Object.keys(mapDispatchToProps)@H_618_35@ // .reduce((@R_764_10586@l,{});@H_618_35@ }

{ bindactioncreators } from './redux'; .... export const connect = (mapStateToProps,context); this.store = context.store; this.state = {}; } componentDidMount(){ this.store.subscribe(this.updatE); this.update(); }

update = () => {@H_618_35@ const state = this.store.getState();@H_618_35@ const filterState = mapStateToProps(statE);

// 调用 API bindactioncreators@H_618_35@ // 对 mapDispatchToProps 内每个 action 创建函数使用 dispatch 进行包裹后返回@H_618_35@ const actionFun = bindactioncreators(mapDispatchToProps,this.store.dispatch);@H_618_35@ this.setState({...filterState,...actionFun});@H_618_35@ }@H_618_35@ render(){@H_618_35@ return <Component {...this.statE} />@H_618_35@ }@H_618_35@ }@H_618_35@ }

五、redux API applymiddleware 的实现@H_489_2@

到此简化版的 react-redux 算是已经初步完成,但是假如我们想要我们的 age 值的增长是一个异步操作,比如:通过按钮点击后经过两秒再修改 age ,而不是一点击按钮就立即修改值;这样我们又该怎么实现呢?

当然我们可以通过 setTimeout 两秒后再执行 action 创建函数,比如这样:

{ setTimeout(()=>{ // 两秒后执行 action 创建函数 this.props.changeAge(); },2000); }

但是呢事实上我们并不愿意像上面那么整,我们想要这么一种效果:我们只需要简单的调用 action 创建函数即可实现异步操作,而不是需要进行额外的操作;这时我们就需要为我们的 react-redux 编写一个中间件来实现这么一个效果;

5.1 准备工作@H_489_2@

在这之前我们所有的 acton 创建函数都是直接返回一个 action 对象,下面我们写一个不一样的 action 创建函数, 它返回的不再是一个 action 对象而是一个函数,并且该函数接收两个参数 dispatch 以及 getState, 在该函数内部我们进行相应的异步操作,比如:修改 age 值;

{ // 返回函数 return (dispatch,getStatE) => { setTimeout(v=>{ console.log('==>',getState()); dispatch({type: 'AGE_GROW'}); },1000); } }
{ changeAge,changeUser,asyncChangeAge } from './actionCreate'; import { connect } from './react-redux';

const mapStateToProps = (statE) => {@H_618_35@ return {user: state.user,age: state.agE};@H_618_35@ }

// 添加 asyncChangeAge@H_618_35@ @connect(mapStateToProps,asyncChangeAgE})@H_618_35@ export default class Demo extends React.Component{@H_618_35@ onChange = (E) => {@H_618_35@ this.props.changeUser(e.target.value);@H_618_35@ }@H_618_35@ onClick = () => {@H_618_35@ this.props.changeAge();@H_618_35@ }@H_618_35@ // 点击事件@H_618_35@ onClickAsync = () => {@H_618_35@ this.props.asyncChangeAge();@H_618_35@ }@H_618_35@ render(){@H_618_35@ return (

user: {this.propS.User},age: {this.props.agE}

user: {/* 新增按钮 */}
); } }

浅谈redux以及react-redux简单实现

5.2 需求实现@H_489_2@

接下来我们先什么都不虑先来实现我们的需求,现在 action 创建函数 asyncChangeAge 因为返回的是一个对象,其 type 值为 undefined 所以当我们点击按钮时 reducer 将会一直匹配到默认情况,返回的将是当前的状态,接下来我们先让我们的 action 创建函数 asyncChangeAge 生效,达到异步修改状态的作用;

既然 asyncChangeAge 返回的不再是一个 action 对象,而是一个函数;那么其实我们要做的事情是很简单的,我们只需要针对 createStore 中的返回值 dispatch 进行一个简单的扩展即可;通过判断 dispatch 中的 action 参数是否是函数而进行不同的操作:

{ ...... // 在createStore 我们对返回值 dispatch 进行了封装 const dispatchExtend = (action) => { if(typeof action === 'function'){ // action 为函数,执行函数 action(dispatch,getStatE); } else { // action 为非函数(对象)调用dispatch dispatch(action); } } return {getState,dispatch: dispatchExtend,subscribE}; }

5.3 抽离封装@H_489_2@

上文我们通过对 createStore 的返回值 dispatch 进行了扩展,实现了 redux-react 的异步操作,但问题是我们将代码写死在 createStore 中了,redux-react 的异步操作应该是一个可选项而不应该是必选项;

新增参数 middleware (函数), 在函数 createStore 开始位置判断 middleware 是否存在,存在则执行;

{ // 判断 middleware 是否存在,存在则执行 if(middlewarE){ return middleware(createStorE)(reducer); }

let state;@H_618_35@ const listeners = [];

const getState = () => {@H_618_35@ return state;@H_618_35@ }

const dispatch = (action) => {@H_618_35@ state = reducer(state,action);@H_618_35@ listeners.forEach(v => v());@H_618_35@ }

const subscribe = (listener) => {@H_618_35@ listeners.push(listener);@H_618_35@ }

dispatch({type: '%$&HJKAJJHDJHJ'});

return {getState,dispatch,subscribE};@H_618_35@ }

(reduX)=> { // 在这里进行创建 store const store = createStore(reduX); // 返回store return {...storE} }

const store = createStore(reducer,applymiddlewarE);

上文 applymiddleware 函数并其实没做任何事情, 只是在 createStore 函数外面套了一层函数,那么接下来我们做点正事,来扩展一下我们的 dispatch

(reduX)=> { const store = createStore(reduX);

const midApi = {@H_618_35@ getState: store.getState,dispatch: (...args) => {dispatch(...args);}@H_618_35@ };

const dispatch = (action) => {@H_618_35@ if( typeof action === 'function' ){@H_618_35@ action(midApi.dispatch,midApi.getStatE);@H_618_35@ } else {@H_618_35@ store.dispatch(action);@H_618_35@ }@H_618_35@ }

return {@H_618_35@ ...store,dispatch@H_618_35@ };@H_618_35@ }

5.4 扩展分离@H_489_2@

上文已经实现了我们想要的效果了,我们在 applymiddleware 对 dispatch 进行了扩展;然而我们是那么容易满足的嘛,当然不是的!! applymiddleware 中对 dispatch 的扩展我们还可以将其单独提出来封装成一个函数;

(createStorE) => (reduX)=> { const store = createStore(reduX);

const midApi = {@H_618_35@ getState: store.getState,dispatch: (...args) => {dispatch(...args);}@H_618_35@ };

const dispatch = middleware(midApi)(store.dispatch);

return {@H_618_35@ ...store,dispatch@H_618_35@ };@H_618_35@ }

next => (action) => { if(typeof action === 'function'){ action(dispatch,getStatE); } else { next(action); } };
ymiddleware(thunk));

5.5 代码整理@H_489_2@

这一步只是将 applymiddleware 函数移到 redux.js 文件中;同时将 thunk 函数写到文件 thunk.jsx 中,然后在 App.js 中引用 applymiddleware 以及 thunk 而已;

浅谈redux以及react-redux简单实现

大佬总结

以上是大佬教程为你收集整理的浅谈redux以及react-redux简单实现全部内容,希望文章能够帮你解决浅谈redux以及react-redux简单实现所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。