React复习(5):模块化项目-待办事项表


一、模块化

模块化即将每个功能区划分出来,典型的mvc框架的代码组织方式,目录结构如下:

在这里插入图片描述
同样,将react-redux项目进行模块化编写可以更方便我们的操作,。

二、待办事项列表项目

1.项目大概

在这里插入图片描述
1)可以显示所有代办事项
2)选择显示完成事项
3)选择显示未完成事项
4)点击删除,删除当前事项
5)点击待办事项内容,可以在完成和未完成间转换,画了横线表示完成了
6)上方可以添加代办事项

2.基本框架

在这里插入图片描述
在src下创建两个功能区,filter用来筛选显示状态;todolist用来做待办事项表的基本操作。
两个功能区都有一个对外接口,index.js文件,这里会将功能区内所有组件、函数等导入到此文件中,这样,功能区外访问时只需在index路径下访问即可。
外部文件index.js根据两个功能区导出的reducer合并后创建store(reducer的合并使用到了combineReducers()函数,具体使用如下图:在这里插入图片描述

第一步框架写完。

3.todoList基本操作分析实现

对于一个待办事项表,我们需要分析一下三点基本操作:
1.添加
添加一个代办事项,相当于更改当前todoList的状态,对于redux更改状态,我们首先想到的是同步更改状态方法dispatch。
首先,在todoList功能区中的reducer文件下设置更改状态的逻辑下(因为两个功能区初始状态不同,所以初始状态直接在reducer中设置,如下rodoList的初始状态为空数组[]):
在这里插入图片描述
在这里详细解释,我们todoList列表应该包含三个属性值:id,text,completed分别表示事项id(便于以后的操作),文本内容,是否完成。三项存于一个数组中todos=[id,text,completed],而action中存储的对象为{type:"",todos:[]},所以reducer中逻辑如上。
到这里,如果我们在外部index文件中使用:

// store.dispatch({type:"ADD_TODOS",todos:{
//   id:1,
//   text:"第一件事",
//   completed:false
// }})

结果如下:
在这里插入图片描述
这里不免想到,id和text是一个变化的属性,不如定义一个方法addTodos去实现,于是在todoList功能区创建action文件,用来表示三种基本操作的函数,首先还是addTodos(只需直接return一个dispatch方法的参数对象{type:"",todos:""}):

var id=0;
const addTodos=function(text){
    return {
        type:"ADD_TODOS",
        todos:{
            id:id++,
            text:text,
            completed:false
        }
    }
}

export {addTodos}

然后store.dispatch(addTodos("第一件事"))调用即可,当然在todoList功能区内,addTodos还是要先引入index在对外暴露。

2.转换(完成<=>未完成)
思路:根据当前选中的id号进行切换,首先在功能区内设置相关行为函数即获取id:
在这里插入图片描述
打印输出获取到的结果:
在这里插入图片描述
之后编写reducer中的改变状态的逻辑(调用一个map方法,即可以返回一个新的数组,遍历state对象中每一个个数组,如果当前数组id与action(即要改变的)的id一致,将completed取反,覆盖原来的item数组值;否则直接返回item数组):
在这里插入图片描述
调用console.log(store.dispatch(toggleTodos(2)))输出:
在这里插入图片描述
3.删除
思路:根据id删除,又是根据id,可以发现基本思路和切换差不多,我们只需对比找到id项,然后去掉即可,于是我们想到了filter方法,reducer逻辑如下(返回一个数组,返回的条件是item.id!=action.id即不是当前选中的id);
在这里插入图片描述
附加上action上的逻辑:
在这里插入图片描述
基本操作和上一步一样。
调用console.log(store.dispatch(delTodos(1)))
结果:
在这里插入图片描述

4.filter基本方法实现

filter功能区是页面点击时触发的相关方法,有三种状态:ALL,Completed,Uncompleted,即页面显示的三个按钮,我们要做的就是,点击按钮,筛选出要显示的数据。
首先,页面初始化state=“ALL”,初始化写在reducer中,原因开头讲过。
然后编写action文件,这个action文件是要传入到dispatch作为参数对象的,所以action文件中函数return一个{type:"",filter:""},具体如下:

const changeFilter=function(filter){
    return {
        type:"CHANGE_FILTER",
        filter:filter
    }
}

export {changeFilter}

将其导入到index中,对外暴露。
action文件写完之后,我们将这种变化通过dispatch传递到filter的reducer中,根据type判断进行什么逻辑,所以具体reducer中逻辑如下:

const reducer=function(state="ALL",action){
    switch(action.type){
        case "CHANGE_FILTER":{
            return action.filter
        }
        default:{
            return state
        }
    }
}

export default reducer

因为filter的初始化state=“ALL",如果想将其改成其他状态,直接return action中的filter即可。最后
调用store.dispatch(changeFilter("COMPLETED"))
控制台输出结果;
在这里插入图片描述

5.视图


1.ToDo组件视图
使用react-redux编写视图部分,首先下载`npm i react-redux --save` 在index文件下引入Provider组件,传入参数store,具体使用见 [React复习(4):React-Redux](https://blog.csdn.net/qq_45856669/article/details/123226329?spm=1001.2014.3001.5502) 然后在TodoList文件下引入connect,规定需要的参数todos,然后使用ul+map渲染,基本js操作。 具体渲染如下:
import React,{Component} from 'react'
import {connect} from 'react-redux'
class TodoList extends Component{
    constructor(props){
        super(props)
    }
    render(){
        console.log(this.props)
        const {todos}=this.props
        return(
            <div>
                <ul>
                    {todos.map((item,index)=>{
                        return <li key={index}>{item.text}</li>
                    })}
                </ul>
            </div>
        )
    }
}
const mapStateToProps=function(state) {
    return {
        todos:state.todos
    }
}
export default connect(mapStateToProps)(TodoList)

渲染结果:
在这里插入图片描述
然后渲染完成事件的效果啊:
在这里插入图片描述
结果如图:
在这里插入图片描述
项目要求根据filter进行显示数据,所以在这里我们还要判断filter,所以自定义函数getTodos(state.todos,state.filter)用来获取我们最终需要渲染的数据给到mapStateToProps函数中,这个函数中就是存放我们需要获取的数据。
具体代码如下(使用filter进行筛选):

const getTodos=function(todos,filter){
    switch(filter){
        case ALL:{
            return todos
        }
        case COMPLETED:{
            return todos.filter((item,index)=>{
                return item.completed==true
            })
        }
        case UNCOMPLETED:{
            return todos.filter((item,index)=>{
                return item.completed==false
            })
        }
        default:{
            return "???"
        }
    }
}
const mapStateToProps=function(state) {
    return {
        todos:getTodos(state.todos,state.filter)
    }
}

结果:
在这里插入图片描述
添加点击事件
点击文本切换事件,和删除按钮的点击事件,我们都在todolist功能区下的action文件下写过,想要调用这些方法,我们就要访问存储他们的地方store,所以通过mapDispatchToProps函数获取这两个函数,获取代码:


const mapDispatchToProps=function(dispatch){
    return{
        onToggleTodos(id){
            dispatch(toggleTodos(id))
        },
        onDelTodos(id){
            dispatch(delTodos(id))
        }
    }
}

其实就是创建函数,函数内部调用store中的逻辑函数,最后记得添加到connect里,然后就是onClick事件的添加:
在这里插入图片描述
两种操作均是根据id进行,所以传入参数id即可,而map中传入item.id即可,最终实现效果。
输入框添加事件
另外设置一个组件,实现添加事件操作。
和TodoList组件相似,需要store的addTodos函数,同是再定义一个mapDispatchToProps,通过connect连接,(注意:mapDispatchToProps是connect的第二个参数,这里不需要第一个参数但也要传递,可以直接传递null)onClick调用即可,组件代码如下:

import React,{Component} from 'react'
import {connect} from 'react-redux'
import { addTodos} from '../action';

class AddTodos extends Component{
    constructor(props){
        super(props)
    }
    render(){
        const {onAddTodos}=this.props
        return (
            <div>
                <input type="text" className="int" />
                <button onClick={()=>{onAddTodos(document.getElementsByClassName("int")[0].value)}}>ADD</button>
            </div>
        )
    }
}

const mapDispatchToProps=function(dispatch) {
    return {
         onAddTodos(text){
             dispatch(addTodos(text))
         }
    }
}
export default connect(null,mapDispatchToProps)(AddTodos)

结果显示:
在这里插入图片描述
应模块化要求,接口统一,在views下再建一个ToDo文件,

import React,{Component} from 'react'
import {connect} from 'react-redux'
import AddTodos from './AddTodos';
import TodoList from './TodoList'


class ToDo extends Component{
    constructor(props){
        super(props)
    }
    render(){
        return (
           <div>
               <AddTodos></AddTodos>
               <TodoList></TodoList>
           </div>
        )
    }
}

export default ToDo

//这里获取input的value值有很多种方式(ref、onChange。。。)


2.Filter组件视图
渲染三个按钮,connect传参,定义mapDispatchToProps函数( 注意注意注意:已经忘了很多遍的事情,mapDispatchToProps定义完不要忘了写到connect中,还有connect第一个参数的传递不要忘了) 组件代码如下:
import React,{Component} from 'react'
import {CHANGE_FILTER} from '../actionType'
import {connect} from 'react-redux'
import {changeFilter} from '../action'
import {ALL,COMPLETED,UNCOMPLETED} from '../../contains'

class Filter extends Component{
    constructor(props){
        super(props)
    }
    render(){
        const {change_Filter}=this.props
        return(
            <div>
                <button onClick={()=>{change_Filter(ALL)}}>All</button> 
                <button onClick={()=>{change_Filter(COMPLETED)}}>Completed</button>
                <button onClick={()=>{change_Filter(UNCOMPLETED)}}>Uncompleted</button>
            </div>
        )
    }
}

const mapDispatchToProps=function(dispatch) {
    return {
        change_Filter(e){
            dispatch(changeFilter(e))
        }
    }
}

export default connect(null,mapDispatchToProps)(Filter)

三、console.log(“END”)

总体过程挺乱的,主要模块化分了太多文件,本项目比较小,所以会感觉非模块化比模块化简单,但对于大项目这个真的很重要。
项目文件如下:

链接:https://pan.baidu.com/s/1psOTedMeYIpHqKk5oZ46jw 
提取码:0hgw
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值