美文网首页
redux学习

redux学习

作者: 回不去的那些时光 | 来源:发表于2020-01-02 21:54 被阅读0次

知识点

action

官方的解释是action是把数据从应用传到 store 的有效载荷,它是 store 数据的唯一来源;要通过本地或远程组件更改状态,需要分发一个action

action type

action的type

reducer

action发出了做某件事的请求,只是描述了要做某件事,并没有去改变state来更新界面,reducer就是根据action的type来处理不同的事件

store

store就是把action和reducer联系到一起的对象,store本质上是一个状态树,保存了所有对象的状态。任何UI组件都可以直接从store访问特定对象的状态

开启redux工具

redux如果要使用google浏览器的redux工具调试,需要在createStore中加入

window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()

案例

创建Redux的仓库store和reducer并使用

默认已经使用 create-react-app 初始化好项目并且已经安装 redux 了

  • 1、在src目录创建store文件夹并在文件夹中创建一个index.js文件
import { createStore } from 'redux' // 引入createStore

const store = createStore()  // 创建数据存储仓库

export default store                // 暴露出去
  • 2、在store文件夹再创建reducer.js文件
const defaultState = {                      // 默认数据
    inputValue: 'Write Something',
    list: [
        '早上6点起床,锻炼身体',
        '晚上跑步一小时'
    ]
}                             

export default (state = defaultState, action) => {  // 就是一个方法函数
    return state
}
  • 3、在store文件夹的index.js文件中引入reducer.js文件

index.js变成这样了

import { createStore } from 'redux' // 引入createStore
// ------------- 重点 ---------------
import reducer from './reducer'     // 引入reducer

const store = createStore(reducer)  // 创建数据存储仓库

export default store                // 暴露出去
  • 4、使用

在使用的文件中引入store,并在构造函数constructor中获取state

import store from './store'

constructor(props) {
    super(props)
    this.state = store.getState()
}

这样 redux 中的数据就和使用的地方产生关联了

加入Redux DevTools插件

在 reducer.js 中加入 window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()

import { createStore } from 'redux' // 引入createStore
import reducer from './reducer'     // 引入reducer

// ----------------- 重点 ----------------
const store = createStore(reducer,
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())  // 创建数据存储仓库

export default store                // 暴露出去

加入这段代码后,就可以使用 redux 调试工具调试数据了

让redux工作起来

redux是管理数据的仓库,现在让他起作用吧!

  • 1、给Input增加onChange事件
<Input 
    onChange={this.changeInputValue} 
    placeholder={this.state.inputValue} 
    style={{ width: '250px', marginRight: '10px' }} />

changeInputValue = (e) => {
    const action = {
        type: 'changeInputValue',
        value: e.target.value
    }
    store.dispatch(action)
}
  • 2、订阅reudx状态
constructor(props) {
    super(props)
    this.state = store.getState()
    // 订阅redux状态
    store.subscribe(this.storeChange)  
}

storeChange = () => {
    this.setState(store.getState())
}
  • 3、在reducer.js中接收传过来的数据
export default (state = defaultState, action) => {  // 就是一个方法函数
    if(action.type === 'changeInputValue') {
        let newState = JSON.parse(JSON.stringify(state))  // 深度拷贝state
        newState.inputValue = action.value
        return newState
    }

    return state
}
  • 4、把两个文件的代码全都贴出来
// TodoList.js
import React, { Component } from 'react'
import 'antd/dist/antd.css'
import { Input, Button, List } from 'antd'
import store from './store'

export default class TodoList extends Component {
    constructor(props) {
        super(props)
        this.state = store.getState()
        // 订阅redux状态
        store.subscribe(this.storeChange)  
    }

    storeChange = () => {
        this.setState(store.getState())
    }

    render() {
        return (
            <div style={{ margin: '10px' }}>
                <div>
                    <Input 
                        onChange={this.changeInputValue} 
                        placeholder={this.state.inputValue} 
                        style={{ width: '250px', marginRight: '10px' }} />
                    <Button type="primary">增加</Button>
                </div>

                <div style={{ margin: '10px', width: '300px' }}>
                    <List
                        bordered
                        dataSource={this.state.list}
                        renderItem={item => (
                            <List.Item>{item}</List.Item>
                        )}
                    >
                    </List>
                </div>
            </div>
        )
    }

    // input输入
    changeInputValue = (e) => {
        const action = {
            type: 'changeInputValue',
            value: e.target.value
        }
        store.dispatch(action)
    }
}
// reducer.js
const defaultState = {                      // 默认数据
    inputValue: 'Write Something',
    list: [
        '早上6点起床,锻炼身体',
        '晚上跑步一小时'
    ]
}                             

export default (state = defaultState, action) => {  // 就是一个方法函数
    if(action.type === 'changeInputValue') {
        let newState = JSON.parse(JSON.stringify(state))  // 深度拷贝state
        newState.inputValue = action.value
        return newState
    }
    return state
}

把 Action Types 抽出来,单独写一个文件

  • 1、在store中新建一个actionTypes.js文件
export const CHANGE_INPUT_VALUE = 'changeInputValue'
export const ADD_ITEM = 'addItem'
export const DELETE_ITEM = 'deleteItem'
  • 2、在TodoList.js中引入并使用
import { CHANGE_INPUT_VALUE, ADD_ITEM, DELETE_ITEM } from './store/actionTypes'

// input输入
changeInputValue = (e) => {
    const action = {
        type: CHANGE_INPUT_VALUE,
        value: e.target.value
    }
    store.dispatch(action)
}

// 点击按钮
clickBtn = () => {
    const action = { 
        type: ADD_ITEM
    }
    store.dispatch(action)
}

// 删除todo
deleteItem = (index) => {
    const action = {
        type: DELETE_ITEM,
        index
    }
    store.dispatch(action)
}
  • 3、在reducer.js中引入并使用
import { CHANGE_INPUT_VALUE, ADD_ITEM, DELETE_ITEM } from './actionTypes'
import { Modal } from 'antd';

const defaultState = {                      // 默认数据
    inputValue: '',
    list: [
        '早上6点起床,锻炼身体',
        '晚上跑步一小时'
    ]
}

export default (state = defaultState, action) => {  // 就是一个方法函数
    // console.log(state ,action)
    if (action.type === CHANGE_INPUT_VALUE) {        // input输入
        let newState = JSON.parse(JSON.stringify(state))  // 深度拷贝state
        newState.inputValue = action.value
        return newState
    }
    if (action.type === ADD_ITEM) {             // 添加item
        let newState = JSON.parse(JSON.stringify(state))
        if (!newState.inputValue) {
            Modal.error({
                title: '提示信息',
                content: '输入框不能为空!'
            });
            return
        }
        newState.list.push(newState.inputValue)
        newState.inputValue = ''
        return newState
    }
    if (action.type === DELETE_ITEM) {              // 删除item
        let newState = JSON.parse(JSON.stringify(state))
        newState.list.splice(action.index, 1)
        return newState
    }

    return state
}

把 Redux Action 抽出来

  • 1、在store中新建actionCreators.js文件
import { CHANGE_INPUT_VALUE, ADD_ITEM, DELETE_ITEM } from './actionTypes'

export const changeInputAction = (value) => ({
    type: CHANGE_INPUT_VALUE,
    value
})

export const addItemAction = () => ({
    type: ADD_ITEM
})

export const deleteItemAction = (index) => ({
    type: DELETE_ITEM,
    index
})
  • 2、修改TodoList.js文件方法
import { changeInputAction, addItemAction, deleteItemAction } from './store/actionCreators'

// input输入
changeInputValue = (e) => {
    // const action = {
    //     type: CHANGE_INPUT_VALUE,
    //     value: e.target.value
    // }
    const action = changeInputAction(e.target.value)
    store.dispatch(action)
}

// 点击按钮
clickBtn = () => {
    // const action = { 
    //     type: ADD_ITEM
    // }
    const action = addItemAction()
    store.dispatch(action)
}

// 删除todo
deleteItem = (index) => {
    // const action = {
    //     type: DELETE_ITEM,
    //     index
    // }
    const action = deleteItemAction(index)
    store.dispatch(action)
}

redux的三个注意要点

  • 1、store必须是唯一的,不能有多个
  • 2、只有store能改变自己的内容,Reducer不能改变
  • 2、Reducer必须是纯函数

相关文章

网友评论

      本文标题:redux学习

      本文链接:https://www.haomeiwen.com/subject/snhaoctx.html