资讯专栏INFORMATION COLUMN

Redux入门0x107: `react`集成`redux`精讲

20171112 / 501人阅读

摘要:这里的其实不需要自己写,已经有好的实现了引入修改组件完整源码组件资源源码

0x000 概述

前面虽然简单的讲了如何在react中集成redux,但是那只是简单的讲讲而已,这一章将会仔细讲讲如何在react中使用reudx

0x001 问题分析

查看前边的栗子:

import {createStore} from "redux"
import React from "react"
import ReactDom from "react-dom"

//reducer
const counter = (state = 0, action) => {
    switch (action.type) {
        case ACTION_INCREMENT:
            return state + 1
        case ACTION_DECREMENT:
            return state - 1
        default:
            return state
    }
}
// action
const ACTION_INCREMENT = "INCREMENT"
const ACTION_DECREMENT = "DECREMENT"
// action creator
const increment = () => ({
    type: ACTION_INCREMENT
})
const decrement = () => ({
    type: ACTION_DECREMENT
})

// store
const store = createStore(counter)

// react
// // 组件
class App extends React.Component {
    constructor() {
        super()
        // 初始化 state
        this.state = {
            counter: 0
        }
        // 监听 store 变化, store 变化的时候更新 counter
        this.unSub=store.subscribe(() => {
            this.setState({
                counter: store.getState()
            })
        })
    }
    // 组件销毁的时候取消订阅
    componentWillUnmount(){
        this.unSub()
    }

    render() {
        return 

{this.state.counter}

} } ReactDom.render( , document.getElementById("app") )

为了让组件可以响应redux的变化,我们写了一些代码:

    ....
    // 监听 store 变化, store 变化的时候更新 counter
    this.unSub=store.subscribe(() => {
        this.setState({
                counter: store.getState()
            })
        })
    ....
    // 组件销毁的时候取消订阅
    componentWillUnmount(){
        this.unSub()
    }

如果我们有大量的组件需要绑定redux,那么写这些代码就显得非常冗余了
这一章要做的事就是优化掉这个东西

0x002 connect方法
这里用了一个reactHOC,参数是一个组件,返回值也是一个组件,但是返回的组件被添加了一个props,也就是stateconnect方法为每个组件添加了响应store数据变化的能力,在store.dispatch调用的时候,会修改组件的props,让组件重绘,从而达到react组件和redux绑定但是又不需要写太多样板代码

connect

const connect = (WrappedComponent) => {
    return class Control extends React.Component {
        constructor() {
            super()
            this.state = {
                state: 0
            }
            this.unSub = store.subscribe(() => {
                this.setState({
                    state: store.getState()
                })
            })
        }

        componentWillUnmount() {
            this.unSub()
        }

        render() {
            return 
        }


    }
}

完整源码

import {createStore} from "redux"
import React from "react"
import ReactDom from "react-dom"

//reducer
const counter = (state = 0, action) => {
    switch (action.type) {
        case ACTION_INCREMENT:
            return state + 1
        case ACTION_DECREMENT:
            return state - 1
        default:
            return state
    }
}
// action
const ACTION_INCREMENT = "INCREMENT"
const ACTION_DECREMENT = "DECREMENT"
// action creator
const increment = () => ({
    type: ACTION_INCREMENT
})
const decrement = () => ({
    type: ACTION_DECREMENT
})

// store
const store = createStore(counter)

const connect = (WrappedComponent) => {
    return class Control extends React.Component {
        constructor() {
            super()
            this.state = {
                state: 0
            }
            this.unSub = store.subscribe(() => {
                this.setState({
                    state: store.getState()
                })
            })
        }

        componentWillUnmount() {
            this.unSub()
        }

        render() {
            return 
        }


    }
}
// 子组件
class SubCom extends React.Component {
    render(){
        return 

{this.props.state}

} } // 包裹这个组件 let ReduxSubCom=connect(SubCom) // react 组件 class App extends React.Component { constructor() { super() } render() { return
} } // 包裹组件 let ReduxApp = connect(App) ReactDom.render( , document.getElementById("app") )

0x003 加强connect方法,消除订阅整个state树的影响
虽然已经实现了将state和组件绑定,但是我们绑定的是整个state,如果state树很大并且组件很多,那这个无畏的性能消耗太凶了。

修改redux结构

const counter = (state = {counter: 0, num: 0}, action) => {
    switch (action.type) {
        case ACTION_INCREMENT:
            return {...state, ...{counter: ++state.counter}}
        case ACTION_DECREMENT:
            return {...state, ...{counter: --state.counter}}
        default:
            return state
    }
}

修改connect方法,返回一个函数,并修改props传参:

const connect = (mapStateToProps) => {
    return (WrappedComponent) => class Control extends React.Component {
        constructor() {
            super()
            this.state = {
                state: {}
            }
            this.unSub = store.subscribe(() => {
                let state = mapStateToProps(store.getState())
                this.setState({
                    state: state
                })
            })
        }
        componentWillUnmount() {
            this.unSub()
        }
        render() {
            return 
        }
    }
}

修改APP组件中的props访问方式

class App extends React.Component {
    constructor() {
        super()
    }
    componentWillReceiveProps(nextProps) {
        console.log(nextProps)
    }
    render() {
        return 

{this.props.counter}

} }

修改connect调用

let ReduxApp = connect((state) => {
    return {
        counter: state.counter
    }
})(App)
0x004: 加强connect,让代码中不再调用store.dispatch,不在依赖redux

修改connect方法,除了吧state映射到props上,也把dispatch给映射上去了,这样组件就感受不到redux的存在了

const connect = (mapStateToProps, mapDispatchToProps) => {

    return (WrappedComponent) => class Control extends React.Component {
        constructor() {
            super()
            // 第一次初始化
            let props = mapStateToProps(store.getState())
            let actions = mapDispatchToProps(store.dispatch)
            this.state = {
                props: {...props,...actions}
            }

            this.unSub = store.subscribe(() => {
                // 变化的时候再次计算
                let props = mapStateToProps(store.getState())
                let actions = mapDispatchToProps(store.dispatch)
                this.setState({
                    props: {...props,...actions}
                })
            })
        }

        componentWillUnmount() {
            this.unSub()
        }

        render() {
            return 
        }
    }
}

修改connect调用,将dispatch映射到组件上

let ReduxApp = connect(
    (state) => {
        return {
            counter: state.counter
        }
    },
    (dispatch) => {
        return {
            increment: () => dispatch(increment()),
            decrement: () => dispatch(decrement()),
        }
    }
)(App)

修改App组件,不再使用store.dispatch,而是使用connect传递过来的dispatch,让组件不依赖redux

class App extends React.Component {
    constructor(props) {
        super()
    }

    render() {
        const {counter,increment,decrement}=this.props
        return 

{counter}

} }

完整源码

import {createStore} from "redux"
import React from "react"
import ReactDom from "react-dom"

//reducer
const counter = (state = {counter: 0, num: 0}, action) => {
    switch (action.type) {
        case ACTION_INCREMENT:
            return {...state, ...{counter: ++state.counter}}
        case ACTION_DECREMENT:
            return {...state, ...{counter: --state.counter}}
        default:
            return state
    }
}
// action
const ACTION_INCREMENT = "INCREMENT"
const ACTION_DECREMENT = "DECREMENT"
// action creator
const increment = () => ({
    type: ACTION_INCREMENT
})
const decrement = () => ({
    type: ACTION_DECREMENT
})

// store
const store = createStore(counter)

const connect = (mapStateToProps, mapDispatchToProps) => {

    return (WrappedComponent) => class Control extends React.Component {
        constructor() {
            super()
            // 第一次初始化
            let props = mapStateToProps(store.getState())
            let actions = mapDispatchToProps(store.dispatch)
            this.state = {
                props: {...props,...actions}
            }

            this.unSub = store.subscribe(() => {
                // 变化的时候再次计算
                let props = mapStateToProps(store.getState())
                let actions = mapDispatchToProps(store.dispatch)
                this.setState({
                    props: {...props,...actions}
                })
            })
        }

        componentWillUnmount() {
            this.unSub()
        }

        render() {
            return 
        }
    }
}

// react 组件
class App extends React.Component {
    constructor(props) {
        super()
    }

    render() {
        const {counter,increment,decrement}=this.props
        return 

{counter}

} } let ReduxApp = connect( (state) => { return { counter: state.counter } }, (dispatch) => { return { increment: () => dispatch(increment()), decrement: () => dispatch(decrement()), } } )(App) ReactDom.render( , document.getElementById("app") )

0x004 reat-redux

以上效果就和上一章的效果一致,是一个counter,在这里我们一步一步去除了样板代码,并将redux从组件中移除,如果只看App组件,根本感觉不到redux的存在,但redux又确实存在,如果有一天你要去掉redux,就可以做到不影响组件了。这里的connect其实不需要自己写,已经有好的实现了:react-redux

// 引入`react-redux`
import {Provider, connect} from "react-redux"
// 修改组件
ReactDom.render(
    
        
    ,
    document.getElementById("app")
)

完整源码

import {createStore} from "redux"
import React from "react"
import ReactDom from "react-dom"
import {Provider, connect} from "react-redux"
//reducer
const counter = (state = {counter: 0, num: 0}, action) => {
    switch (action.type) {
        case ACTION_INCREMENT:
            return {...state, ...{counter: ++state.counter}}
        case ACTION_DECREMENT:
            return {...state, ...{counter: --state.counter}}
        default:
            return state
    }
}
// action
const ACTION_INCREMENT = "INCREMENT"
const ACTION_DECREMENT = "DECREMENT"
// action creator
const increment = () => ({
    type: ACTION_INCREMENT
})
const decrement = () => ({
    type: ACTION_DECREMENT
})

// store
const store = createStore(counter)


// react 组件
class App extends React.Component {
    constructor(props) {
        super()
    }

    render() {
        const {counter, increment, decrement} = this.props
        return 

{counter}

} } let ReduxApp = connect( (state) => { return { counter: state.counter } }, (dispatch) => { return { increment: () => dispatch(increment()), decrement: () => dispatch(decrement()), } } )(App) ReactDom.render( , document.getElementById("app") )

0x005 资源

源码

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108509.html

相关文章

  • Redux入门0x106: `react`、`vue`、`原生 js`集成`redux`

    摘要:概述之前写的所有关于的文章都是纯粹的,是和框架无关环境无关的,所以我没有将和一起讲,为的是吧和分开,作为独立的个体来分析,提现的是一种思想,而不是一个思维定式。而现在我们可以尝试在中来使用了。 0x000 概述 之前写的所有关于redux的文章都是纯粹的redux,是和框架无关、环境无关的redux,所以我没有将redux和react一起讲,为的是吧redux和react分开,作为独立...

    BetaRabbit 评论0 收藏0
  • Router入门0x205: react-route + redux + react 集成

    摘要:概述这一章终于大集成了集成源码效果说明集成主要是用到库集成源码效果说明主要用到库,是针对库在环境下的封装组件,注入等属性接管跟组件指定路由和组件的对应关系集成源码引入相关的包和链接组件效果说明主要用到库都是用的接 0x000 概述 这一章终于大集成了 0x001 集成react 源码 import React from react import ReactDom from rea...

    yiliang 评论0 收藏0
  • Redux入门教程(快速上手)

    摘要:接下来演示不变性打开终端并启动输入。修改代码如下我们使用在控制台中打印出当前的状态。可以在控制台中确认新的商品已经添加了。修改和文件最后,我们在中分发这两个保存完代码之后,可以在浏览器的控制台中检查修改和删除的结果。 典型的Web应用程序通常由共享数据的多个UI组件组成。通常,多个组件的任务是负责展示同一对象的不同属性。这个对象表示可随时更改的状态。在多个组件之间保持状态的一致性会是一...

    amuqiao 评论0 收藏0
  • 前端学习资源

    摘要:提供了完整的环境,并且支持自定义域名指向,动态计算资源调整,可以完成各种应用的开发编译与部署。 react 新特性 react16 Context 算法相关 图解排序算法(二)之希尔排序 微信小程序 微信小程序组件化的解决方案移动端尺寸基本知识 浏览器 前端必读:浏览器内部工作原理浏览器缓存原理解读浏览器加载css和js及dom解析之间的关系浏览器缓存 CSS学习 移动web开发布局入...

    zhisheng 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<