大佬教程收集整理的这篇文章主要介绍了浅谈redux以及react-redux简单实现,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态)。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。
管理不断变化的 state 非常困难。如果一个 model 的变化会引起另一个 model 变化,那么当 view 变化时,就可能引起对应 model 以及另一个 model 的变化,依次地,可能会引起另一个 view 的变化。直至你搞不清楚到底发生了什么。state 在什么时候,由于什么原因,如何变化已然不受控制。 当系统变得错综复杂的时候,想重现问题或者添加新功能就会变得举步维艰。
如果这还不够糟糕,考虑一些来自前端开发领域的新需求,如更新调优、服务端渲染、路由跳转前请求数据等等。前端开发者正在经受前所未有的复杂性,难道就这么放弃了吗?当然不是。
这里的复杂性很大程度上来自于:我们总是将两个难以理清的概念混淆在一起:变化和异步。 如果把二者分开,能做的很好,但混到一起,就变得一团糟。一些库如 React 试图在视图层禁止异步和直接操作 DOM 来解决这个问题。美中不足的是,React 依旧把处理 state 中数据的问题留给了我们自己。而 redux 就可以来帮我管理这些状态;
首先我们先结合 reducer 以及 action 的知识简单实现开头展示的 demo,并逐步揭晓 createStore 的神秘面纱;
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@ }
); } }其实上文的代码中对于 createStore 的实现原理已经基本描述清除,下面我们只是单纯的对代码进行了简单的封装;当然为了能够获取到 state 我们专门增加了一个函数 getState 来实现它;
// 获取状态@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@ }
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@ }
); } }在 react 中大多数情况下我们需要将状态传递给后代组件进行使用的,当然通过 props 是可以实现状态从父级到子级的传递,但是当状态需要传递的层级比较深的情况下再使用 props 就显得无力了,那么在 react-redux 中它是如何实现对 store 的传递的呢?
// 创建 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
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@ }
); } }通过 react context 我们实现了对 store 的传递,到这里 Provider 的功能以及实现原理基本上应该算是清晰了,无非就是对组件进行包裹同时通过 react context 来传递共享 store;那么接下来我们通过对代码的封装来实现 Provider 组件;
// 设置 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@ }
// 创建 store@H_618_35@ const store = createStore(reducer);
class App extends Component {@H_618_35@
render() {@H_618_35@
// 调用接口 Provider@H_618_35@
return
上文中在后代组件如果需要获取 store 则需要手动通过获取 react context 来调用 store 并且需要显性的调用 store 内部的方法来进行一些操作;接下来我们来实现这么一个高阶组件 connect,我们只需要提供所需的 redux state 以及 action 创建函数,即可通过 props 获取到相应的 redux state,并且允许直接通过 props 调用action 创建函数来试图修改 redux state ;
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@ }
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@ }
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@ }
// 编写 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 (
); } }在上文我们对 mapDispatchToProps 的处理过程就是 API bindactioncreators 的功能: 将给定 action 创建函数使用 dispatch 进行包裹后返回;
return actionFun;@H_618_35@ // 一种简写方式: 骚操作@H_618_35@ // return actionFun = Object.keys(mapDispatchToProps)@H_618_35@ // .reduce((@R_764_10586@l,{});@H_618_35@ }
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@ }
到此简化版的 react-redux 算是已经初步完成,但是假如我们想要我们的 age 值的增长是一个异步操作,比如:通过按钮点击后经过两秒再修改 age ,而不是一点击按钮就立即修改值;这样我们又该怎么实现呢?
当然我们可以通过 setTimeout 两秒后再执行 action 创建函数,比如这样:
但是呢事实上我们并不愿意像上面那么整,我们想要这么一种效果:我们只需要简单的调用 action 创建函数即可实现异步操作,而不是需要进行额外的操作;这时我们就需要为我们的 react-redux 编写一个中间件来实现这么一个效果;
在这之前我们所有的 acton 创建函数都是直接返回一个 action 对象,下面我们写一个不一样的 action 创建函数, 它返回的不再是一个 action 对象而是一个函数,并且该函数接收两个参数 dispatch 以及 getState, 在该函数内部我们进行相应的异步操作,比如:修改 age 值;
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 (
); } }接下来我们先什么都不考虑先来实现我们的需求,现在 action 创建函数 asyncChangeAge 因为返回的是一个对象,其 type 值为 undefined 所以当我们点击按钮时 reducer 将会一直匹配到默认情况,返回的将是当前的状态,接下来我们先让我们的 action 创建函数 asyncChangeAge 生效,达到异步修改状态的作用;
既然 asyncChangeAge 返回的不再是一个 action 对象,而是一个函数;那么其实我们要做的事情是很简单的,我们只需要针对 createStore 中的返回值 dispatch 进行一个简单的扩展即可;通过判断 dispatch 中的 action 参数是否是函数而进行不同的操作:
上文我们通过对 createStore 的返回值 dispatch 进行了扩展,实现了 redux-react 的异步操作,但问题是我们将代码写死在 createStore 中了,redux-react 的异步操作应该是一个可选项而不应该是必选项;
新增参数 middleware (函数), 在函数 createStore 开始位置判断 middleware 是否存在,存在则执行;
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@ }
上文 applymiddleware 函数并其实没做任何事情, 只是在 createStore 函数外面套了一层函数,那么接下来我们做点正事,来扩展一下我们的 dispatch
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@ }
上文已经实现了我们想要的效果了,我们在 applymiddleware 对 dispatch 进行了扩展;然而我们是那么容易满足的嘛,当然不是的!! applymiddleware 中对 dispatch 的扩展我们还可以将其单独提出来封装成一个函数;
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@ }
这一步只是将 applymiddleware 函数移到 redux.js 文件中;同时将 thunk 函数写到文件 thunk.jsx 中,然后在 App.js 中引用 applymiddleware 以及 thunk 而已;
以上是大佬教程为你收集整理的浅谈redux以及react-redux简单实现全部内容,希望文章能够帮你解决浅谈redux以及react-redux简单实现所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。