react实现todomvc

react实现todomvc,第1张

在学习了 react 的父子组件通讯后,尝试着做了一个大致如下的 todomvc 案例:

这里关于 todomvc 的基本结构及样式就不去过多的描述了

我们可以去 github todumvc 样板

上进行下载其基本的结构

大致结构如下:

index.js

/**
 * 1. 导入react和react-dom
 * 2. 创建 react 元素
 * 3. 把 react 元素渲染到页面
 */
 import React from 'react';
 import ReactDom from 'react-dom/client';
 import { Component } from 'react';
 import './styles/base.css';
 import './styles/index.css'

 class App extends Component {
     render() {
         return (
            
todos
0 item left All Active Completed
) } } // 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样 const element = ( ); // 参数1:渲染的 react 元素即虚拟 DOM // 参数2:需要渲染到哪个容器中 const root = ReactDom.createRoot(document.getElementById('root')); root.render(element);

接着我们需要做的就是将其进行组件化拆分,大致分为如下三个部分:

在 src 目录下新建 components 文件夹,专门用来存放组件

将 src/index.js 文件进行如上图拆分

components/TodoHeader.js

import React,{ Component } from 'react';

export default class TodoHeader extends Component {
    render() {
        return (
            
todos
) } }

components/TodoMain.js

import React,{ Component } from 'react';

export default class TodoHeader extends Component {
    render() {
        return (
            
) } }

 components/TodoFooter.js

import React,{ Component } from 'react';

export default class TodoHeader extends Component {
    render() {
        return (
            
0 item left All Active Completed
) } }

index.js

/**
 * 1. 导入react和react-dom
 * 2. 创建 react 元素
 * 3. 把 react 元素渲染到页面
 */
 import React from 'react';
 import ReactDom from 'react-dom/client';
 import { Component } from 'react';
 import './styles/base.css';
 import './styles/index.css'
 import TodoHeader from './components/TodoHeader';
 import TodoMain from './components/TodoMain';
 import TodoFooter from './components/TodoFooter';

 class App extends Component {
     render() {
         return (
            
) } } // 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样 const element = ( ); // 参数1:渲染的 react 元素即虚拟 DOM // 参数2:需要渲染到哪个容器中 const root = ReactDom.createRoot(document.getElementById('root')); root.render(element);

在完成了上面的步骤之后,从这里开始,正式进行案例的开发

首先,我们需要实现的就是 任务列表渲染功能

这里需要先在父组件(index.js)里准备数据,然后传递到子组件(TodoMain.js)里进行展示,就需要用到组件通讯里的父传子:

父组件提供要传递的state数据

给子组件标签添加属性,值为 state 中的数据

子组件中通过 props 接收父组件中传递的数据

注意:接收数据:函数组件通过参数props接收数据,类组件通过this.props接收数据

 TodoMain.js

import React,{ Component } from 'react';

export default class TodoHeader extends Component {
    render() {
        const { list } = this.props;
        return (
            
{ list.map(item => { return ( ) }) }
) } }

index.js

/**
 * 1. 导入react和react-dom
 * 2. 创建 react 元素
 * 3. 把 react 元素渲染到页面
 */
 import React from 'react';
 import ReactDom from 'react-dom/client';
 import { Component } from 'react';
 import './styles/base.css';
 import './styles/index.css'
 import TodoHeader from './components/TodoHeader';
 import TodoMain from './components/TodoMain';
 import TodoFooter from './components/TodoFooter';

 class App extends Component {
     state = {
         list: [
             {
                 id: 1,
                 name: 'JavaScript',
                 done: false
             },
             {
                id: 2,
                name: 'Vue',
                done: false
            },
            {
                id: 3,
                name: 'react',
                done: true
            }
         ]
     }
     render() {
         const { list } = this.state;
        //  console.log(list);
         return (
            
) } } // 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样 const element = ( ); // 参数1:渲染的 react 元素即虚拟 DOM // 参数2:需要渲染到哪个容器中 const root = ReactDom.createRoot(document.getElementById('root')); root.render(element);

其次,我们需要实现的就是 删除任务功能

 当点击删除按钮时,实现删除

这就需要给每个 li 注册点击事件,实现删除

但是需要注意的就是 li 的渲染是在 TodoMain.js 里的,而数据是在 index.js(父组件)里,因此就需要用到组件通信里的子传父通过当前点击的 id 进行删除

思路:利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数。

父组件提供一个回调函数(用于接收数据)

将该函数作为属性的值,传递给子组件

子组件通过 props 调用回调函数

将子组件的数据作为参数传递给回调函数

index.js

/**
 * 1. 导入react和react-dom
 * 2. 创建 react 元素
 * 3. 把 react 元素渲染到页面
 */
 ...

 class App extends Component {
     state = {
         ...
     }
     render() {
         ...
         
         ...
     }
     delTodoById = (id) => {
         this.setState({
             list: this.state.list.filter(item => item.id !== id)
         })
     }
 }


...

TodoMain.js

import React,{ Component } from 'react';

export default class TodoHeader extends Component {
    render() {
        const { list } = this.props;
        return (
            
... { list.map(item => { return ( ... ... ) }) }
) } // 删除 del = (id) => { // console.log(id); this.props.delTodoById(id); } }

然后,我们需要实现的就是 任务状态修改功能

这个主要就是改变 checked  的一个状态即可

但是状态的改变是定义在index.js(父组件)的state里的--done

因此只能通过组件通讯中的子传父的形式进行传递,将当前点击的那个id,传递给父组件,在父组件里找到并修改对应id的done值

index.js

/**
 * 1. 导入react和react-dom
 * 2. 创建 react 元素
 * 3. 把 react 元素渲染到页面
 */
 ...
 class App extends Component {
     state = {
         list: [
             {
                 id: 1,
                 name: 'JavaScript',
                 done: false
             },
             {
                id: 2,
                name: 'Vue',
                done: false
            },
            {
                id: 3,
                name: 'react',
                done: true
            }
         ]
     }
     render() {
         const { list } = this.state;
         return (
            ...
			
			...
         )
     }
     // 修改任务状态
     updateDone = (id) => {
         this.setState({
             list: this.state.list.map(item => {
                 if(item.id === id){
                    return {
                        ...item,
                        done: !item.done
                    };
                 }else {
                     return item;
                 }
             })
         })
     }
 }


// 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样
const element = (
    
        
    
);
  
// 参数1:渲染的 react 元素即虚拟 DOM
// 参数2:需要渲染到哪个容器中
const root = ReactDom.createRoot(document.getElementById('root'));
root.render(element);

TodoMain.js

import React,{ Component } from 'react';

export default class TodoHeader extends Component {
    render() {
        const { list } = this.props;
        return (
            
... { list.map(item => { return ( ... this.updateDone(item.id)} /> ... ) }) }
) } // 修改任务状态 updateDone = (id) => { this.props.updateDone(id); } }

接着,我们需要实现的是 添加任务 功能

对于这个功能的实现主要利用的就是键盘的回车事件

在 TodoHeader.js 中通过 value 拿到值

但是数据的增加是在 index.js 里的,也就是最终需要把数据添加到 index.js(父组件)的 list 里,因此就需要用到组件通讯中的子传父

import React,{ Component } from 'react';

export default class TodoHeader extends Component {
    state = {
        name: ''
    }
    render() {
        return (
            
todos
) } // 添加任务 addTas = (e) => { this.setState({ name: e.target.value }) } addTo = (e) => { // 按下回车键后才触发 if(e.keyCode !== 13){ return; } if(!this.state.name.trim()){ return alert('任务不能为空!'); } // 添加 todo this.props.addTo(this.state.name); // 清空 name this.setState({ name: '' }) } }

index.js

/**
 * 1. 导入react和react-dom
 * 2. 创建 react 元素
 * 3. 把 react 元素渲染到页面
 */
...

 class App extends Component {
     state = {
         list: [
             {
                 id: 1,
                 name: 'JavaScript',
                 done: false
             },
             {
                id: 2,
                name: 'Vue',
                done: false
            },
            {
                id: 3,
                name: 'react',
                done: true
            }
         ]
     }
     render() {
         const { list } = this.state;
         return (
           ...
            
			...
         )
     }
     ...
     // 添加任务
     addTo = (name) => {
        //  console.log(name);
        this.setState({
            list: [{
                id: Date.now(),
                name: name,
                done: false
            } ,
            ...this.state.list]
        })
     }
 }


// 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样
const element = (
    
        
    
);
  
// 参数1:渲染的 react 元素即虚拟 DOM
// 参数2:需要渲染到哪个容器中
const root = ReactDom.createRoot(document.getElementById('root'));
root.render(element);

紧接着,我们需要实现的就是 双击显示 修改框

为了准确找到当前双击的这个id ,在 TodoMain.js 里通过 state 保存了一个当前双击的那个任务的 id 的状态(currentId),将当前双击的这个 id 传进去

当双击 lable 标签之后,拿到其对应的 id,并且保存到 currentId 里

在 li 里去判断 item.id 是否等于 currentId 但是这里需要同时控制两个 类名,因此我们需要通过 npm install classnames 下载 classnames

TodoMain.js

import React,{ Component } from 'react';
import classnames from 'classnames';

export default class TodoHeader extends Component {
    state = {
        // 存放当前双击的id
        currentId: ''
    }
    render() {
        const { list } = this.props;
        return (
            
... { list.map(item => { return ( ... ... ) }) }
) } ... // 双击显示修改框 showEdit = (id) => { // console.log(id); this.setState({ currentId: id }) } }

 

实现双击回显任务名称

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1323782.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-12
下一篇 2022-06-12

发表评论

登录后才能评论

评论列表(0条)

保存