Redux 入门

学习 Redux 是个十分痛苦的过程,因为你有可能不知道 Redux 和 React-Redux 是两个不同的东西,而且一堆看起来很新的概念总能把新手绕晕。

这篇文章将从一个简单的例子开始讲 Redux 到底要怎么使用。建议先学习 EventHub 或者看我的另一篇文章 React 的兄弟组件通信,因为 Redux 的主要思想就是 EventHub 思想。

纯 JS + Redux

先说下需求,首先要有一个数字,点击按钮数字加1,没了。不过这个过程要使用到 Redux,也就是说这个数字要放在全局变量中。

这里就用一个简单的 index.html 写就完了。HTML 代码如下:

<div id="app"></div>

接下来写 JS。

function add() {
    store.dispatch({ type: 'add', payload: 1 }) // 1. dispatch 一个 action
}

function render() {
    let app = document.querySelector('#app')
    app.innerHTML = `
    Clicked: <span id="value">${store.getState()}</span> times
    <div>
        <button id="add" onclick="add1()">+1</button>
    </div> `
}

function stateChanger(state, action) {
    if (state === undefined) {
       return 0
    }
    else {
        if (action.type === 'add') {
            let newState = state + action.payload
            return newState // 2. 根据操作生成新的 state 触发一个事件
        }
    }
}

let store = Redux.createStore(stateChanger)

render(store)
store.subscribe(render) // 3. 接收到事件,重新 render

这里说明一下运行的步骤:

  1. 首先运行 render() 将标签都 append 到 document 上,并在按钮上绑定 add 回调
  2. 点击了按钮执行 add() ,然后 dispatch 一个 action(相当于触发了名为“add”的一个事件)
  3. 因为在 Redux.createStore(stateChanger) 时,Redux 会监听 action(也就是事件)的触发,所以会执行 stateChanger 里的代码
  4. 因为在 store.subscribe(render) 在 if-else 里修改了新的 state 后,Redux 会重新执行 render() 函数,从而更新整个页面

Redux 的用法就是这么简单!但是为什么我们看官方档看得想死呢?因为加了 React,后来的所有看起来很变态的使用方法都是为了解决:怎么让代码更好分离,怎么获取全局变量等。思想还是那个思想。

React + Redux

现在我们正式加入 React,使用官方提供的create-react-app来创建应用。App 组件写成这样:

// App.js
class App extends Component {
    add1() {
        this.props.store.dispatch({  // 1. dispatch 一个 action
            type: 'add',
            payload: 1
        })
    }
    render() {
        return (
            <div className="App">
                Clicked: <span id="value">{this.props.value}</span> times
                <div>
                    <button id="add1" onClick={this.add1.bind(this)}>+1</button>
                </div>
            </div>
        )
    }
}

export default App

在入口文件去初始化 Redux:

const stateChanger = (state, action) => {
    if (state === undefined) {
        return 0
    }
    else {
        if (action.type === 'add') {
            let newState = state + action.payload
            return newState // 2. 根据操作生成新的 state 触发一个事件
        }
        else {
            return state
        }
    }
}

function render() {
    ReactDOM.render(
        <App
            value={store.getState()}
            store={store}
        />,
        document.getElementById('root')
    )
}

const store = createStore(stateChanger)

store.subscribe(render) // 3. 接收到事件,重新 render

render()

感觉好像没什么变化呀,不就将一个 index.html 分成了 index.js 和 App.js 么?但是这里涉及到怎么去获取 store 的问题。

如果一两个组件就用 props 来传 store 就好了,但是如果组件很深,那么 store 就要像传家保一样一层层往下传,十分麻烦。

为了解决这个问题, React 社区又推出了一个新的工具:React-Redux。注意这个和 Redux 没有太大关系。为了说明这两个是不一样,我放下他们的官网:Redux 官网React-Redux 官网

React + Redux + React-Redux

先说明这个工具就只是用来让别的组件可以访问到 store 而已,所以它只有 4 个API,其中主要我们要用的就 2 个:Provider, connect。简单理解:

  1. Provider:将 store 放在顶层组件
  2. connect:将 store 里的数据和 dispatch action (也就是触发事件)和当前组件绑定,使得该组件可以自由访问和修改 store

现在修改上面两个文件:

// index.js
const stateChanger = (state, action) => {
    if (state === undefined) {
        return { n: 0 }
    }
    else {
        if (action.type === 'add') {
            let newState =  {
                n: state.n + action.payload
            }
            return newState
        }
        else {
            return state
        }
    }
}

const store = createStore(stateChanger)

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root')
)

下面的 App.js

class App extends Component {
    render() {
        return (
            <div className="App">
                Clicked: <span id="value">{this.props.n}</span> times
                <div>
                    <button id="add" onClick={this.props.add.bind(this)}>+1</button>
                </div>
            </div>
        )
    }
}

// 将部分 store 里的 state 映射到 props 上
function mapStateToProps(state) {
    return {
        n: state.n
    }
}

// 将 dispatch action 相关操作映射到 props 上
function mapDispatchToProps(dispatch) {
    return {
        add: () => {
            dispatch({ type: 'add', payload: 1 })
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

来对比一下两份代码:

少了哪些?

  1. 不用 store.subscribe(render),Provider 会在更新值后自动重新渲染
  2. 不用在组件 App 里写回调函数了,在 mapDispatchToProps 里声明事件,这个事件会就负责调用 dispatch(action)

多了哪些?

  1. 要在 App 组件外再去套一层 <Provider/>
  2. 将 App 组件和 state,调用 dispatch 的函数连接起来。连接(映射)后的结果是,所有 state 数据和调用 dispatch 的函数都可以从 this.props 得到

这样就解决了组件访问,修改 store 里的 state 问题。唉,绕了一大圈就为了搞这些事。

那些变态概念

Redux 为什么这么难,是因为它将很简单的概念给了个新名字罢了。

Redux

  1. Store:存放全局数据的一个东西,但是要通过 store.getState() 来获取全局数据
  2. State:全局数据
  3. Action:对应 EventHub 里的事件,actionType 就是事件名,payload 就是传入的数据
  4. Dispatch:触发事件,如 dispatch({ type: 'add', payload: 1}),就是指触发一个名为“add”的事件,并带上了数据 1
  5. Reducers:对应触发事件后的回调函数,如我们平时听到的onError = xxx,这个 xxx 就是 Reducer,这个例子的 Reducer 就是 stateChanger

React-Redux

  1. Provider:可以看成一个包住最外面 App 的一个标签,这个标签传入 store 后,通过某些方法所有组件都可以访问到 store
  2. mapStateToProps:将存在 store 里的数据放在这个组件的 props 上
  3. mapDispatchToProps:将需要调用 dispatch 的函数放在这个组件的 props 上
  4. connect:将上面两个东西和这组件联系起来

是不是很烦,嗯,我也是这么觉得的,明明很简单的概念,就是不好好说话。
(完)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,999评论 4 368
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,102评论 1 302
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,709评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,439评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,846评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,881评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,062评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,783评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,517评论 1 248
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,762评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,241评论 1 264
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,568评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,236评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,145评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,941评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,965评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,802评论 2 275

推荐阅读更多精彩内容