枯燥的Redux 完成todolist

文件目录

枯燥的Redux 完成todolist

Index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Todolist from './Todolist'
//以上都是固定格式

import {Provider} from 'react-redux'//被provider包裹的都可以获得store里面的值
import store from './store'
const App = (//提供器,包裹所有需要的组件
    <Provider store={store}>
        <Todolist />
    </Provider>
)

ReactDOM.render(App, document.getElementById('root'))
// ReactDOM.render(<Todolist />, document.getElementById('root'))

react-redux还需要安装
注意修改render里面的值,之前事todolist主文件的闭合标签,现在是一个提供器。

Todolist.js

引入

import React, { Component } from 'react';
import store from './store/index'
import TodolistUI from './TodolistUI'
import {changeInputAction,addItemAction,deleteItemAction,getMyListAction} from './store/actionCreators'
import {connect} from 'react-redux'

TodolistUI是将页面组件部分拆分出了的一个文件。
actionCreators是一个action的定义空间。
connect是redux的一个组件。


class代码

class Todolist extends Component {
    //     //console.log(store.getState())//获取仓库里面的值
    //    // store.subscribe(this.storeChange)//subscribe监听store中每次修改情况
    // 
    render() { 
        return (
            <TodolistUI 
                inputValue={this.props.inputValue}
                changeInputeValue={this.props.changeInputValue}
                clickbtn = {this.props.clickBtn}
                list = {this.props.list}
                deleteItem={this.props.deleteItem}
            />
        );
    }
    componentDidMount(){//axios需要在声明周期函数内进行
    //    const action = getTodoList()
    //    store.dispatch(action)
    const action = getMyListAction()
    store.dispatch(action)
    console.log(action)
    }  

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

由于connect具有监听store的功能subscribe监听就没有用了

TodoListUI为展示组件,由于使用了connect,this.state变成了this.props。

axios异步交互需要放在生命周期函数内执行。
componentDidMount的执行期是在render后面执行,是在组件已经完全挂载到网页上才会调用被执行,所以可以保证数据的加载。

connect的两个组件

const stateToProps =(state)=>{
    return {
        inputValue:state.inputValue,
        list:state.list
    }
}
const dispatchToProps = (dispatch)=>{
    return{
        changeInputValue(e) {
            let action = changeInputAction(e.target.value)
            dispatch(action)
        },
        clickBtn(){
            let action = addItemAction()
            dispatch(action)
        },
        deleteItem(index){
            const action = deleteItemAction(index)
            dispatch(action)
        }
    }
}
export default connect(stateToProps,dispatchToProps)(Todolist);//两个参数都表示映射关系

第一个参数负责将通过state获得的数据映射到展示组件的this.props
第二个参数负责将用户操作转化为Action的功能函数映射到展示组件的this.props

第一个参数具有监听store的功能。

TodolistUI

引入

import React from 'react';//不需要component的函数就不用写{ Component }
import 'antd/dist/antd.css' 
import {Input,Button ,List} from 'antd'

UI组件主要是一些页面展示
该组件采用了ant design的模板。引入了input,list和button

//无状态组件没有state,性能更强一些。
const TodolistUI=(props)=>{
    return ( 
        <div style={{margin:'10px'}}>
            <div>
                <Input 
                    placeholder = {props.inputValue}
                    style={{width:'250px',marginRight:'10px'}}  
                    onChange={props.changeInputeValue}
                />
                <Button 
                    type="primary" //antd 里的Primary按钮
                    onClick={props.clickbtn}
                >
                    增加
                </Button>
            </div>
            <div style={{margin:'10px',width:'300px'}}>
                <List 
                    bordered//边框
                    dataSource = {props.list}//变量都是固定格式。
                    renderItem={(item,index)=>(<List.Item onClick={()=>{props.deleteItem(index)}}>{item}</List.Item>)}//List.item 是List的一个固定标签
                    //不声明,函数内用item,
                >
                </List>
            </div>
        </div>
    );
}
 
export default TodolistUI;

除render外,没有其他函数,所以采用无状态组件。


无状态组件

无状态组件不存在state,只会有props,也就没有生命周期函数,所以性能比有状态组件强。


由Todolist可知,Todolist向UI组件内传入值,props接收值。


Store文件夹

index.js

Saga

import {createStore , applyMiddleware , compose} from 'redux'
import Reducer from './reducer'
//import thunk from 'redux-thunk'
import creatSagaMiddleware from 'redux-saga'
import mySagas from './sagas'
const sagaMiddleware = creatSagaMiddleware()

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}):compose

const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware))//thunk

const store = createStore(Reducer,enhancer)//creatStore只能传两个参数,所以利用compose增强函数
sagaMiddleware.run(mySagas)//saga专属
export default store

采用的是saga进行异步加载,引入creatSagaMiddleware用于创造中间件。
saga需要额外建立一个文件进行操作。
composeEnhancers主要是用来检测有没有用reduxtools,(用于检查redux的插件。)

applyMiddleware redux自带的函数,返回store对象,
sagaMiddleware.run(mySagas) saga需要运行另一个执行文件

sagas.js

import { takeEvery,put } from 'redux-saga/effects'//默认格式
import { GET_MY_LIST } from './actionTypes'
import {getListAction} from './actionCreators'
import axios from 'axios'
function* mySaga(){
    yield takeEvery(GET_MY_LIST,getList)//等待监听
}

function* getList(){
    const res = yield axios.get('https://mock.yonyoucloud.com/mock/17500/demo1/xiaojiejie')
    const action = getListAction(res.data)
    yield put(action)
}
//generator
export default mySaga

yield takeEvery(GET_MY_LIST,getList) GET_MY_LIST是在页面组件加载完成之后才进行的。(getMyListAction就是GET_MY_LIST),在componentDidMount里面执行,也就是在页面组件加载完成之后进行的。
枯燥的Redux 完成todolist
GET_MY_LIST作用后,getlist开始作用了。获取接口,然后用 put 将action传入reducer,然后getListAction 获取list列表并返回给UI组件。

reducer.js

import {CHANGE_INPUT,ADD_ITEM,DELTE_ITEM, GET_LIST} from './actionTypes'
const defaultState = {
    inputValue:'Write Something',
    list:[]
}
export default (state = defaultState,action)=>{
    //Reducer里只能接收state,不能改变state。
    if(action.type===CHANGE_INPUT){
        let newState = JSON.parse(JSON.stringify(state))//创建一个局部变量,修改局部变量来代替修改state
        newState.inputValue = action.value//action为传递过来的值 dispatch
        return newState  //newState的inputValue已经是新输入了的
    }
    if(action.type===ADD_ITEM){
        let newState = JSON.parse(JSON.stringify(state))
        newState.list.push(newState.inputValue)
        newState.inputValue=''
        return newState
    }
    if(action.type===DELTE_ITEM){
        let newState = JSON.parse(JSON.stringify(state))
        newState.list.splice(action.index,1)
        return newState
    }
    if(action.type===GET_LIST){
        let newState = JSON.parse(JSON.stringify(state))
        newState.list = action.data.data//action 为传入的值,action.data表示的是action里面的数据,action.data.data才是接口里面的属性
        return newState
    }
    return state
}

引入的都是一些命名格式。
let newState = JSON.parse(JSON.stringify(state)) 相当于深度克隆。

actionTypes.js

export const CHANGE_INPUT ='changeInpute'//全大写的是常量  
export const ADD_ITEM= 'addItem'
export const DELTE_ITEM = 'deleteItem'
export const GET_LIST = 'getList'
export const GET_MY_LIST='getMyList'

将action的type命名规范化。

actionCreators.js

import {CHANGE_INPUT, GET_MY_LIST}  from './actionTypes'
import {ADD_ITEM}  from './actionTypes'
import {DELTE_ITEM}  from './actionTypes'
import {GET_LIST}  from './actionTypes'
export const changeInputAction = (value)=>({
    type:CHANGE_INPUT,
    value
})
export const addItemAction = ()=>({
    type:ADD_ITEM
})

export const deleteItemAction = (index)=>({
    type:DELTE_ITEM,
    index
})

export const getListAction = (data)=>({
    type:GET_LIST,
    data
})
export const getMyListAction = (data) =>({
    type:GET_MY_LIST
})
上一篇:Linux 高级I/O函数-sendfile


下一篇:再次对redux进行研究