前端(十):redux进阶之褪去react-redux的外衣

一、context实现数据传递

  在react中,props和state都可以设置数据。不同的是,props借助组件属性传递数据但不可以渲染组件,它相对来说是“静态的”;state可以监听事件来修改数据并重新渲染组件,它相对来说是“动态的”。要想实现组件间传递数据并且可以根据state重新渲染组件,就必须一层层地传递props和this.state。

  redux借助context这个全局API,以及内置的getChildContext方法简化了数据传递。context是一个全局的变量,getChildContext让react有能力向context中写入数据,并让当前组件的所有子组件能够从中获取到数据。

  如果在context中传递state状态,那么context的数据就会根据state状态的变化而变化,子组件也会跟着被重新渲染。

import React from ‘react‘import PropTypes from ‘prop-types‘

class SubOneChild extends React.Component{    static contextTypes = {        number: PropTypes.number    };    render(){        return <h2> { this.context.number } </h2>    }}

class SubOne extends React.Component{    static contextTypes = {        number: PropTypes.number    };    render(){        console.log(this.context);        return (            <div>                <h4> SubOne: { this.context.number }</h4>                <SubOneChild />            </div>        )    }}

class App extends React.Component{    // 使用context必须要对数据类型进行校验    static childContextTypes = {        number: PropTypes.number    };    constructor(props){        super(props);        this.state = {            number: 10        }    }    // 使用getChildContext向context传递数据    getChildContext(){        return this.state    }    handleChange(){        this.setState({            number: this.state.number + 1        })    }    render(){        return (            <div>                <h2>App: { this.state.number }</h2>                <button onClick={()=>this.handleChange()}>点击增加</button>                <SubOne />            </div>        )    }}export default App

  上例并没有使用props传递this.state.number,而是通过context实现了数据的传递。它将数据传递简化为两步:第一步,父组件向context注入state数据并规定context数据协议,第二部,任意层级的子组件根据同样的context数据协议获取数据。

二、实现同步react-redux

  react-redux做了两步:将整个ReactDOM要渲染的组件用Provider包裹起来,只用Provider向context注入state数据;任意组件通过connect从props中获取state数据和sction事件。

// src/my-react-redux.jsimport React from ‘react‘import PropTypes from ‘prop-types‘

// 1.仿写reduxexport function createStore(reducer) {    let currentState = {};    let currentListeners = [];    function getState() {        return currentState;    }    function subscribe(listener) {        currentListeners.push(listener);    }    function dispatch(action) {        currentState = reducer(currentState, action);        currentListeners.forEach(v=>v())    }    dispatch({type: ‘@#$%^&*(‘});  // 执行一遍获取默认state    return { getState, subscribe, dispatch }}

// 2.仿写react-redux

// Provider: 把store写到context里,全局只包裹一次,这样所有的子元素都可以取到store

export class Provider extends React.Component{  // 规定数据协议    static childContextTypes = {        store: PropTypes.object    };  // 从Provider属性中获取过来store    constructor(props, context){        super(props, context);        this.store = props.store;    }  // 向context中传递当前组件的store,以允许任意子组件都可以获取这个store    getChildContext(){        return { store: this.store }    }  // 返回被包裹的组件    render(){        return this.props.children    }}

// connect接收组件,更新redux数据放到组件的属性里

// export function connect(mapStateToProps, mapDispatchToProps) {//     return function (WrapComponent) {//         return class ConnectComponent extends React.Component{}//     }// }

// 上述带参数的装饰器的简便写法export const connect = (mapStateToProps=state=>state, mapDispatchToProps={})=>(WrapComponent)=>{    return class ConnectComponent extends React.Component{    // 规定context数据协议        static contextTypes = {            store: PropTypes.object        };    // 注意要继承context,在state中设置props参数来接收最外层父组件向context中传递的数据         constructor(props, context){            super(props, context);            this.state = {                props: {}            }        }    // 获取store,并调用store的监听函数,来监听一个事件;监听后要执行一次更新来渲染一次组件         componentDidMount(){            const { store } = this.context;            store.subscribe(()=>this.update());  // 监听数据变化            this.update();        }    // 主函数,主要调用store.dispatch(action)方法来更新store以及中间组件ConnectComponent的状态ConnectComponentConCthis.state.props          update(){            const { store } = this.context;            const stateProps = mapStateToProps(store.getState());            const dispatchProps = ConnectComponent.bindActionCreator(mapDispatchToProps, store.dispatch);            this.setState({          // 因为props会被重写,一定要注意这里的顺序                 props: {                    ...this.state.props,                    ...stateProps,                    ...dispatchProps                }            })        }        static bindActionCreator(mapDispatchToProps, dispatch){            let event = {};            Object.keys(mapDispatchToProps).forEach(v=>{                let func = mapDispatchToProps[v];                event[v] = (...args)=>dispatch(func(...args)); // 注意把func的参数传进来,用dispatch调用func            });            return event        }        render(){// 将中间组件ConnectComponent的state透传给被包裹的组件            return <WrapComponent { ...this.state.props } />        }    }};

  把reducer重写一下:

// src/my-reducer.js

const ADD = ‘ADD‘;const REDUCE = ‘REDUCE‘;export function reducer(state=0, action) {    // action都是事件类型    switch(action.type){        case ADD:            return state + 1;        case REDUCE:            return state - 1;        default:            return 10    }}export function add() {    return { type: ADD }}export function reduce() {    return { type: REDUCE }}

  app.js中内容改写为:

// src/my-app.jsimport React from ‘react‘import { connect } from "./my-react-redux";import { add, reduce } from "./my-reducer";

@connect(state=>({number:state}))class SubOneChild extends React.Component{    render(){        return <p> { this.props.number } </p>    }}@connect(state=>({number:state}))class SubOne extends React.Component{    render(){        return (            <div>                <h3> SubOne: { this.props.number }</h3>                <SubOneChild />            </div>        )    }}@connect(state=>({number:state}), { add, reduce})  // 以对象的方式获取stateclass App extends React.Component{    render(){        // console.log(this.props);        return (            <div>                <h1>App: { this.props.number }</h1>                <button onClick={this.props.add}>点击增加</button>                <SubOne />            </div>        )    }}export default App

  在index.js中引入App。

// src/index.jsimport React from ‘react‘import ReactDOM from ‘react-dom‘import { reducer } from ‘./my-reducer‘import {createStore, Provider} from ‘./my-react-redux‘import App from ‘./my-app‘

const store = createStore(reducer);ReactDOM.render(    <Provider store={ store }>        <App />    </Provider>,    document.getElementById(‘root‘));

  其大致流程图如下:

  

原文地址:https://www.cnblogs.com/kuaizifeng/p/9425406.html

时间: 2024-11-08 19:37:55

前端(十):redux进阶之褪去react-redux的外衣的相关文章

React+Redux学习笔记:React+Redux简易开发步骤

前言 React+Redux 分为两部分: UI组件:即React组件,也叫用户自定义UI组件,用于渲染DOM 容器组件:即Redux逻辑,处理数据和业务逻辑,支持所有Redux API,参考之前的文章:Redux学习笔记:Redux简易开发步骤 而React+Redux是以上两部分结合起来,方便在React中使用Redux,专用库为React-Redux.js.React-Redux.js新增了一些新方法: Provider:容器跟组件,可直接把外部的state传递给所有子组件和UI组件: m

ReactJS React+Redux+Router+antDesign通用高效率开发模板,夜间模式为例

工作比较忙,一直没有时间总结下最近学习的一些东西,为了方便前端开发,我使用React+Redux+Router+antDesign总结了一个通用的模板,这个技术栈在前端开发者中是非常常见的. 总的来说,我这个工程十分便捷,对于初学者来说,可能包含到以下的一些知识点: 一.React-Router的使用 Router是为了方便管理组件的路径,它使用比较简单,一般定义如下就行,需要注意的是,react-router的版本有1.0-3.0,各个版本对应的API大致相似,但也有不同,我使用的是2.X的,

6周学习计划,攻克JavaScript难关(React/Redux/ES6 etc.)

6周学习计划,攻克JavaScript难关(React/Redux/ES6 etc.) 余博伦· 2 个月前 原文链接:A Study Plan To Cure JavaScript Fatigue 作者:Sacha Greif 和大家一样,最近我也看了Jose Aguinaga写的How it feels to learn JavaScript in 2016. 显然这篇文章击中了人们的痛处.它在Hacker News上排了不止一次第一.同样也是/r/javascript上最火的一篇,在Med

react案例-&gt;新闻移动客户端--(react+redux+es6+webpack+es6的spa应用)

今天分享一个react应用,应在第一篇作品中说要做一个react+redux+xxx的应用.已经做完一部分,拿出来分享.github地址为:点我就可以咯~ 这里实现了一个新闻移动站的spa.本来想写pc端的,但是比较懒,而且因为主要是react的项目,关于css和布局的细节就是糊弄人的了.T.T,这里只说关于这个项目的js部分. 这里的功能很简单,有一下几点: 1,按”心“排序 当比上一个多了,就会排到前面. 2.评论部分 新闻的评论部分类似qq空间的评论 当然,也可以点击新闻回复的哦. ===

利用 React/Redux/React-Router 4/webpack 开发大型 web 项目时如何按需加载

如何设计一个大型 web 项目? React + webpack 如何按需加载? React + React-Router 4 + webpack 如何按需加载? React + Redux + React-Router 4 + webpack 如何按需加载? 实录提要: bundle-loader 和 Webpack 内置的 import() 有什么区别? 按需加载能否支持通过请求后台数据,动态配置页面的的应用场景? 参与过几个 React 项目,被依赖包搞的晕晕的,不知道该怎么选择? 什么包

react redux 深入剖析--干货

## 技术栈: react + redux + webpack + react-router + ES6/7/8 + immutable ## 运行项目(nodejs 6.0+) ``` git clone https://github.com/bailicangdu/react-pxq.git cd react-pxq npm i 或者运行 yarn(推荐) npm start npm run build (发布)``` ## 说明 > 本项目主要用于理解 react 和 redux 的编译方

react+redux渲染性能优化原理

大家都知道,react的一个痛点就是非父子关系的组件之间的通信,其官方文档对此也并不避讳: For communication between two components that don't have a parent-child relationship, you can set up your own global event system. Subscribe to events in componentDidMount(), unsubscribe in componentWillU

react+redux官方实例TODO从最简单的入门(6)-- 完结

通过实现了增-->删-->改-->查,对react结合redux的机制差不多已经了解,那么把剩下的功能一起完成吧 全选 1.声明状态,这个是全选状态 2.action约定 3.reducers,更新store 4.底层组件实现函数 5.上层组件数据传递 到这里全选的功能就实现了 显示action的数量和删除completed操作 整过过程一模一样 1. 2. 3. 4.(展示action数量的view) (删除completed的view) 放到Footer中 在上层父组件进行数据通信

react + redux 完整的项目,同时写一下个人感悟

先附上项目源码地址和原文章地址:https://github.com/bailicangd... 做React需要会什么? react的功能其实很单一,主要负责渲染的功能,现有的框架,比如angular是一个大而全的框架,用了angular几乎就不需要用其他工具辅助配合,但是react不一样,他只负责ui渲染,想要做好一个项目,往往需要其他库和工具的配合,比如用redux来管理数据,react-router管理路由,react已经全面拥抱es6,所以es6也得掌握,webpack就算是不会配置也