04 todoList案例

news2024/9/27 21:28:10

React全家桶

一、案例- TODO List 综合案例

在这里插入图片描述

功能描述

  1. 动态显示初始列表
  2. 添加一个 todo
  3. 删除一个 todo
  4. 反选一个 todo
  5. todo 的全部数量和完成数量
  6. 全选/全不选 todo
  7. 删除完成的 todo

1.1 静态组件构建

  • 将资料包中的todos_page/index.html中核心代码添加到Todo.jsx文件中,并将class修改成className。
  • 创建todo.css样式文件,并在将资料包中的css文件中内容copy到该文件中,并导入
import React from 'react'
import "./todo.css"
export default function Todo() {
    return (
        <div className="todo-container">
            <div className="todo-wrap">
                <div className="todo-header">
                    <input type="text" placeholder="请输入你的任务名称,按回车键确认" />
                </div>
                <ul className="todo-main">
                    <li>
                        <label>
                            <input type="checkbox" />
                            <span>xxxxx</span>
                        </label>
                        <button className="btn btn-danger">删除</button>
                    </li>
                    <li>
                        <label>
                            <input type="checkbox" checked />
                            <span className="done">yyyy</span>
                        </label>
                        <button className="btn btn-danger">删除</button>
                    </li>
                </ul>
                <div className="todo-footer">
                    <label>
                        <input type="checkbox" />
                    </label>
                    <span>
                        <span>已完成0</span> / 全部2
                    </span>
                    <button className="btn btn-danger">清除已完成任务</button>
                </div>
            </div>
        </div>
    )
}
  • 在将该组件导入到App.jsx中
import React from 'react'
import Todo from './TODO/Todo'
export default function App() {
  return <Todo />
}

1.2 静态组件拆分

当某一个组件功能复用性非常高的时候,咱们需要考虑将其进行拆分成具体的组件进行复用,

在本实例中只是本着模块化的思想进行拆分。

1.2.1 拆分头部

  • 在TODO文件夹中创建一个TodoHeader文件夹,将关于头部的组件代码进行拆分
import React from 'react'
import "./TodoHeader.css"
export default function TodoHeader() {
    return (
        <div className="todo-header">
            <input type="text" placeholder="请输入你的任务名称,按回车键确认" />
        </div>
    )
}
  • 将todo.css中关于header头部的样式也拆分出来,单独创建一个TodoHeader.css文件
/*header*/
.todo-header input {
    width: 560px;
    height: 28px;
    font-size: 14px;
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 4px 7px;
}

.todo-header input:focus {
    outline: none;
    border-color: rgba(82, 168, 236, 0.8);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}
  • 在Todo.jsx文件导入并调用组件
import React from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
export default function Todo() {
    return (
        <div className="todo-container">
            <div className="todo-wrap">
                <TodoHeader />
                ...
            </div>
        </div>
    )
}

1.2.2 拆分中间

  • 在TODO文件夹中创建一个TodoMain文件夹,将关于中间的组件代码进行拆分
import React from 'react'
import './TodoMain.css'
export default function TodoMain() {
    return (
        <ul className="todo-main">
            <li>
                <label>
                    <input type="checkbox" />
                    <span>xxxxx</span>
                </label>
                <button className="btn btn-danger">删除</button>
            </li>
            <li>
                <label>
                    <input type="checkbox" checked />
                    <span className="done">yyyy</span>
                </label>
                <button className="btn btn-danger">删除</button>
            </li>
        </ul>
    )
}
  • 将todo.css中关于Main中间的样式也拆分出来,单独创建一个TodoMain.css文件
/*main*/
.todo-main {
    margin-left: 0px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding: 0px;
}

.todo-empty {
    height: 40px;
    line-height: 40px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding-left: 5px;
    margin-top: 10px;
}

/*item*/
li {
    list-style: none;
    height: 36px;
    line-height: 36px;
    padding: 0 5px;
    border-bottom: 1px solid #ddd;
}

li label {
    float: left;
    cursor: pointer;
}

li label li input {
    vertical-align: middle;
    margin-right: 6px;
    position: relative;
    top: -1px;
}

li button {
    float: right;
    display: none;
    margin-top: 3px;
}

li:before {
    content: initial;
}

li:last-child {
    border-bottom: none;
}

li .done {
    color: #666;
    text-decoration: line-through;
}
  • 在Todo.jsx文件导入并调用组件
import React from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
export default function Todo() {
    return (
        <div className="todo-container">
            <div className="todo-wrap">
                <TodoHeader />
                <TodoMain />
                ....
            </div>
        </div>
    )
}

1.2.3 拆分底部

  • 在TODO文件夹中创建一个TodoFooter文件夹,将关于底部的组件代码进行拆分
import React from 'react'
import "./TodoFooter.css"
export default function TodoFooter() {
    return (
        <div className="todo-footer">
            <label>
                <input type="checkbox" />
            </label>
            <span>
                <span>已完成0</span> / 全部2
            </span>
            <button className="btn btn-danger">清除已完成任务</button>
        </div>
    )
}

  • 将todo.css中关于Footer底部的样式也拆分出来,单独创建一个TodoFooter.css文件
/*footer*/
.todo-footer {
    height: 40px;
    line-height: 40px;
    padding-left: 6px;
    margin-top: 5px;
}

.todo-footer label {
    display: inline-block;
    margin-right: 20px;
    cursor: pointer;
}

.todo-footer label input {
    position: relative;
    top: -1px;
    vertical-align: middle;
    margin-right: 5px;
}

.todo-footer button {
    float: right;
    margin-top: 5px;
}

  • 在Todo.jsx文件导入并调用组件
import React from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
import TodoFooter from './TodoFooter/TodoFooter'
export default function Todo() {
    return (
        <div className="todo-container">
            <div className="todo-wrap">
                <TodoHeader />
                <TodoMain />
                <TodoFooter />
            </div>
        </div>
    )
}

1.3 关于数据与状态的分析

首先,TodoMain组件中的数据肯定是循环显示在组件中,

而且还可以通过文本框输入提交进行修改和删除按钮一系列操作,

不难分析数据是变化的,那么咱们可以将这个数据的初始记录在state状态中。

其次,状态中记录的值是一个数组,里面每一个任务是一个对象,里面的done用来标识是否选中状态

[
	{id:1,title:'任务1',done:false},
	{id:2,title:'任务2',done:false}
]

1.4 任务列表的数据渲染展示

  • 在Todo.jsx文件中创建初始化状态值,并将状态值通过组件标签属性的方式传递给相应的子组件
export default function Todo() {
    //记录状态
    let [todolists, changetodos] = useState([
        { id: 1, title: '任务1', done: false },
        { id: 2, title: '任务2', done: true }
    ]);
    return (
        <div className="todo-container">
            <div className="todo-wrap">
                <TodoHeader />
                <TodoMain todolists={todolists} />
                <TodoFooter />
            </div>
        </div>
    )
}

  • 在TodoMain.jsx组件中接收父组件传递的属性属性,并进行循环渲染
import React from 'react'
import './TodoMain.css'
export default function TodoMain(props) {
    //函数式组件中子组件接收父组件中的属性
    //函数的参数名称自定义,只不过一般props含义为属性
    //对象解构赋值
    let { todolists } = props;
    return (
        <ul className="todo-main">
            {
                todolists.map(item => {
                    return <li key={item.id}>
                        <label>
                            <input type="checkbox" checked={item.done} />
                            <span className={item.done ? 'done' : ""}>{item.title}</span>
                        </label>
                        <button className="btn btn-danger">删除</button>
                    </li>
                })
            }

        </ul>
    )
}

1.5 新增任务功能

1.5.1 给Header子组件添加受控

  • 在TodoHeader.jsx文件中添加受控组件,给文本框绑定onChange事件以及value属性
  • 并添加onKeyDown事件,通过事件对象中的keyCode属性来判断用户按下的按键是什么
  • 接收父组件传递的组件属性,用来修改父组件中的状态数据
import React, { useState } from 'react'
import "./TodoHeader.css"
export default function TodoHeader(props) {
    let { addTodo } = props;
    //声明状态
    let [title, setTitle] = useState('')
    let keyDown = (e) => {
        //通过事件对象中的keyCode属性来判断,用户敲下的是回车键
        if (e.keyCode === 13) {
            // 新增一个任务
            addTodo(e.target.value);
            //清空文本框中的value值
            setTitle('');
        }
    }
    let changeValue = (e) => {
        setTitle(e.target.value)
    }
    return (
        <div className="todo-header">
            <input type="text"
                placeholder="请输入你的任务名称,按回车键确认"
                onKeyDown={keyDown} value={title} onChange={changeValue} />
        </div>
    )
}

1.5.2 父组件传递属性到子组件

import React, { useState } from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
import TodoFooter from './TodoFooter/TodoFooter'
export default function Todo() {
    //记录状态
    let [todolists, changetodos] = useState([
        { id: 1, title: '任务1', done: false },
        { id: 2, title: '任务2', done: true }
    ]);
    let addTodo = (title) => {
        changetodos([
            ...todolists,
            {
                id: todolists.length + 1,
                title,
                done: false
            }
        ])
    }
    return (
        <div className="todo-container">
            <div className="todo-wrap">
                <TodoHeader addTodo={addTodo} />
                <TodoMain todolists={todolists} />
                <TodoFooter />
            </div>
        </div>
    )
}

1.6 点击任务复选框修改任务状态功能

  • 先在子组件中添加onChange事件,确保程序运行没有报错,但是子组件没办法直接修改父组件中的数据,

    仍然需要父组件通过调用子组件时通过属性进行传递

import React from 'react'
import './TodoMain.css'
export default function TodoMain(props) {
    //函数式组件中子组件接收父组件中的属性
    //函数的参数名称自定义,只不过一般props含义为属性
    //对象解构赋值
    let { todolists } = props;

    let changeDone = () => {
        
    }
    return (
        <ul className="todo-main">
            {
                todolists.map(item => {
                    return <li key={item.id}>
                        <label>
                            <input type="checkbox" checked={item.done}
                                onChange={changeDone} />
                            <span className={item.done ? 'done' : ""}>{item.title}</span>
                        </label>
                        <button className="btn btn-danger">删除</button>
                    </li>
                })
            }

        </ul>
    )
}

  • 在父组件中添加一个修改状态的方法,并传递到子组件
import React, { useState } from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
import TodoFooter from './TodoFooter/TodoFooter'
export default function Todo() {
    //前面代码省略
	...
    //定义一个可以修改状态的方法
    let modifyTodo = (id, done) => {
        //注意:在这里咱们要修改状态时,在changetodos()里面需要传入一个修改状态后的新数组
        //React会将原数组以及修改状态后的新数组进行比较
        let newtodo = todolists.map(item => {
            if (item.id === id) {
                item.done = done;
            }
            return item;
        })
        changetodos(newtodo)
    }

    return (
        <div className="todo-container">
            <div className="todo-wrap">
                <TodoHeader addTodo={addTodo} />
                <TodoMain todolists={todolists} modifyTodo={modifyTodo} />
                <TodoFooter />
            </div>
        </div>
    )
}

  • 子组件接收父组件传递的属性,并进行修改
import React from 'react'
import './TodoMain.css'
export default function TodoMain(props) {
    //函数式组件中子组件接收父组件中的属性
    //函数的参数名称自定义,只不过一般props含义为属性
    //对象解构赋值
    let { todolists, modifyTodo } = props;

    let changeDone = (id) => {
        return (e) => {
            modifyTodo(id, e.target.checked);
        }
    }
    return (
        <ul className="todo-main">
            {
                todolists.map(item => {
                    return <li key={item.id}>
                        <label>
                            <input type="checkbox" checked={item.done}
                                onChange={changeDone(item.id)} />
                            <span className={item.done ? 'done' : ""}>{item.title}</span>
                        </label>
                        <button className="btn btn-danger">删除</button>
                    </li>
                })
            }

        </ul>
    )
}

1.7 删除任务以及空状态提示

  • 在子组件中给删除按钮添加点击事件
import React from 'react'
import './TodoMain.css'
export default function TodoMain() {
    //省略前面代码...
    //声明删除功能函数
    let remove = () => {
       
    }
    return (
        <ul className="todo-main">
            {
                todolists.map(item => {
                    return <li key={item.id}>
                        <label>
                            <input type="checkbox" checked={item.done}
                                onChange={changeDone(item.id)} />
                            <span className={item.done ? 'done' : ""}>{item.title}</span>
                        </label>
                        <button className="btn btn-danger" onClick={remove}>删除</button>
                    </li>
                })
            }
        </ul>
    )
}


  • 在父组件中将需要删除的项通过属性传递到子组件中
import React, { useState } from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
import TodoFooter from './TodoFooter/TodoFooter'
export default function Todo() {
    //省略前面代码...
    //声明要删除的函数
    let removeTodo = (id) => {
    	//利用数组中的过滤方法,将不满足传递的要删除的id值以外的所有的项过滤出来
        let newtodo = todolists.filter(item => item.id !== id);
        changetodos(newtodo)
    }
    return (
        <div className="todo-container">
            <div className="todo-wrap">
                <TodoHeader addTodo={addTodo} />
                <TodoMain todolists={todolists} removeTodo={removeTodo} modifyTodo={modifyTodo} />
                <TodoFooter />
            </div>
        </div>
    )
}

  • 子组件根据父组件传递的属性进行接收,并执行
import React from 'react'
import './TodoMain.css'
export default function TodoMain(props) {
    //函数式组件中子组件接收父组件中的属性
    //函数的参数名称自定义,只不过一般props含义为属性
    //对象解构赋值
    let { todolists, modifyTodo, removeTodo } = props;

    let changeDone = (id) => {
        return (e) => {
            modifyTodo(id, e.target.checked);
        }
    }
    let remove = (id) => {
        return (e) => {
            removeTodo(id);
        }
    }
    return (
        <ul className="todo-main">
            {
                todolists.map(item => {
                    return <li key={item.id}>
                        <label>
                            <input type="checkbox" checked={item.done}
                                onChange={changeDone(item.id)} />
                            <span className={item.done ? 'done' : ""}>{item.title}</span>
                        </label>
                        <button className="btn btn-danger" onClick={remove(item.id)}>删除</button>
                    </li>
                })
            }
        </ul>
    )
}

  • 当将所有的任务全部删除后,页面没有任何数据,所以我们需要一个适当的提示

    在子组件的虚拟DOM结构中添加一个li

return (
        <ul className="todo-main">
            {
                todolists.map(item => {
                    return <li key={item.id}>
                        <label>
                            <input type="checkbox" checked={item.done}
                                onChange={changeDone(item.id)} />
                            <span className={item.done ? 'done' : ""}>{item.title}</span>
                        </label>
                        <button className="btn btn-danger" onClick={remove(item.id)}>删除</button>
                    </li>
                })
            }
             {todolists.length === 0 && <li className='empty'>暂无相关任务</li>}
        </ul>
    )

在TodoMain.css中设置empty的相关样式

/* 删除 */
li.empty {
    text-align: center;
    padding: 20px 0;
}

1.8 全选与全不选的效果

1.8.1 点击全选按钮

  • 先给子组件中的复选框绑定一个 onChange事件
import React from 'react'
import "./TodoFooter.css"
export default function TodoFooter() {
    let changeAll = () => {
        
    }
    return (
        <div className="todo-footer">
            <label>
                <input type="checkbox" onChange={changeAll} />
            </label>
            <span>
                <span>已完成0</span> / 全部2
            </span>
            <button className="btn btn-danger">清除已完成任务</button>
        </div>
    )
}


  • 父组件声明函数,将其通过子组件属性进行传递
import React, { useState } from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
import TodoFooter from './TodoFooter/TodoFooter'
export default function Todo() {
  	//省略之前代码...
  	//声明函数
    let checkAllTodo = (done) => {
        let newtodo = todolists.map(item => {
            item.done = done;
            return item;
        })
        changetodos(newtodo)
    }
    return (
        <div className="todo-container">
            <div className="todo-wrap">
                <TodoHeader addTodo={addTodo} />
                <TodoMain todolists={todolists} removeTodo={removeTodo} modifyTodo={modifyTodo} />
                <TodoFooter checkAllTodo={checkAllTodo} />
            </div>
        </div>
    )
}


  • 子组件接收属性并调用
import React from 'react'
import "./TodoFooter.css"
export default function TodoFooter(props) {
    let { checkAllTodo } = props;
    let changeAll = (e) => {
        checkAllTodo(e.target.checked);
    }
    return (
        <div className="todo-footer">
            <label>
                <input type="checkbox" onChange={changeAll} />
            </label>
            <span>
                <span>已完成0</span> / 全部2
            </span>
            <button className="btn btn-danger">清除已完成任务</button>
        </div>
    )
}

1.8.2 点击每一项复选框选中全选框

  • 父组件将状态数组传递到TodoFooter组件中
<TodoFooter checkAllTodo={checkAllTodo} todolists={todolists} />

  • 子组件进行接收,当循环每一项中的复选框都选中了则全选框选中,反之不选中

    并且考虑到当删除每一项之后,全选框也不应该选中,设定条件为数组长度不能为0

import React from 'react'
import "./TodoFooter.css"
export default function TodoFooter(props) {
    let { checkAllTodo, todolists } = props;
    let changeAll = (e) => {
        checkAllTodo(e.target.checked);
    }
    return (
        <div className="todo-footer">
            <label>
                <input type="checkbox" onChange={changeAll}
                    checked={todolists.every(item => item.done) && todolists.length > 0}
                />
            </label>
            <span>
                <span>已完成0</span> / 全部2
            </span>
            <button className="btn btn-danger">清除已完成任务</button>
        </div>
    )
}


  • 实现底部任务统计效果
<span>已完成 {todolists.filter(item => item.done).length}</span> / 全部 {todolists.length}

1.9 移除已完成任务

  • 给子组件中的按钮添加点击事件
import React from 'react'
import "./TodoFooter.css"
export default function TodoFooter() {
	//省略之前代码...
    let clear = () => {
       
    }
    return (
        <div className="todo-footer">
            //省略之前代码...
            <button className="btn btn-danger" onClick={clear}>清除已完成任务</button>
        </div>
    )
}

  • 父组件传递方法到子组件
import React, { useState } from 'react'
import "./todo.css"
import TodoHeader from './TodoHeader/TodoHeader'
import TodoMain from './TodoMain/TodoMain'
import TodoFooter from './TodoFooter/TodoFooter'
export default function Todo() {
    //省略之前代码....
    let removeAllTodo = () => {
        let newtodo = todolists.filter(item => !item.done);
        changetodos(newtodo)
    }
    return (
        <div className="todo-container">
            <div className="todo-wrap">
                <TodoHeader addTodo={addTodo} />
                <TodoMain todolists={todolists} removeTodo={removeTodo} modifyTodo={modifyTodo} />
                <TodoFooter
                    checkAllTodo={checkAllTodo}
                    todolists={todolists}
                    removeAllTodo={removeAllTodo} />
            </div>
        </div>
    )
}

  • 子组件接收并执行
import React from 'react'
import "./TodoFooter.css"
export default function TodoFooter(props) {
    let { checkAllTodo, todolists, removeAllTodo } = props;
    let changeAll = (e) => {
        checkAllTodo(e.target.checked);
    }
    let clear = () => {
        removeAllTodo();
    }
    return (
        <div className="todo-footer">
            <label>
                <input type="checkbox" onChange={changeAll}
                    checked={todolists.every(item => item.done) && todolists.length > 0}
                />
            </label>
            <span>
                <span>已完成 {todolists.filter(item => item.done).length}</span> / 全部 {todolists.length}
            </span>
            <button className="btn btn-danger" onClick={clear}>清除已完成任务</button>
        </div>
    )
}

1.10 修复KEY重复的BUG

  • npm i nanoid
  • 在Todo.jsx文件中引入
import { nanoid } from 'nanoid'

  • 修改添加任务时id的值,调用nanoid方法
{
    id: nanoid(),
        title,
        done: false
}

1.11 封装TodoItem组件

  • 在Todo文件夹下创建TodoItem子文件夹,并在其中创建TodoItem.jsx文件,将TodoMain循环项代码拆分
import React from 'react'
export default function TodoItem() {
    return (
        <li key={item.id}>
            <label>
                <input type="checkbox" checked={item.done}
                    onChange={changeDone(item.id)} />
                <span className={item.done ? 'done' : ""}>{item.title}</span>
            </label>
            <button className="btn btn-danger" onClick={remove(item.id)}>删除</button>
        </li>
    )
}


  • TodoMain父组件中导入TodoItem子组件,并将需要的数据传递
import React from 'react'
import './TodoMain.css'
import TodoItem from '../TodoItem/TodoItem';
export default function TodoMain(props) {
    //函数式组件中子组件接收父组件中的属性
    //函数的参数名称自定义,只不过一般props含义为属性
    //对象解构赋值
    let { todolists, modifyTodo, removeTodo } = props;
    return (
        <ul className="todo-main">
            {
                todolists.map(item => {
                    return <TodoItem modifyTodo={modifyTodo} removeTodo={removeTodo} item={item} key={item.id} />
                })
            }
            {todolists.length === 0 && <li className='empty'>暂无相关任务</li>}

        </ul>
    )
}

  • 子组件接收父组件传递的数据
import React from 'react'

export default function TodoItem(props) {
    let { modifyTodo, removeTodo, item } = props;
    let changeDone = (id) => {
        return (e) => {
            modifyTodo(id, e.target.checked);
        }
    }
    let remove = (id) => {
        return (e) => {
            removeTodo(id);
        }
    }
    return (
        <li key={item.id}>
            <label>
                <input type="checkbox" checked={item.done}
                    onChange={changeDone(item.id)} />
                <span className={item.done ? 'done' : ""}>{item.title}</span>
            </label>
            <button className="btn btn-danger" onClick={remove(item.id)}>删除</button>
        </li>
    )
}

1.12 React中发送ajax请求

以英雄联盟数据列表为例

  • 安装axios
npm i axios

  • 创建一个Heros目录并添加Heros.jsx文件
import React from 'react'
import axios from 'axios'
import { useEffect } from 'react'
import { useState } from 'react'
export default function Hero() {
    let [heros, setHeros] = useState([]);
    //在组件挂载完成时执行
    useEffect(() => {
        /* axios.get('http://api.xiaohigh.com/heros').then(value => {
            console.log(value.data);
        }) */

        async function main() {
            let result = await axios.get('http://api.xiaohigh.com/heros');
            console.log(result)
            setHeros(result.data);
        }
        main()
    }, [])
    return (
        <div className='hero-container container'>
            <h2 className='page-header'>英雄列表</h2>
            <div className="row">
                {
                    heros.map(item => {
                        return <div className="col-xs-1" key={item.id}>
                            <img className='img-responsive' src={`http://cdn.xiaohigh.com${item.big_image}`} alt="" />
                            <p className='text-center'>{item.name}</p>
                        </div>
                    })
                }


            </div>
        </div>
    )
}

1.13 json-server启动服务

  • 在当前案例项目中根目录创建一个server文件夹,并添加一个db.json文件,将之前初始化状态数据copy进来
{
    "todos":[
        { "id": 1, "title": "任务", "done": false },
        { "id": 2, "title": "任务2", "done": true }
    ]
}
  • 在server文件夹下终端运行服务
json-server --watch db.json --port 3001 #可以利用json-server --help来查看参数

注:如果使用json-server时报错,有可能是没有安装json-server

使用全局安装:npm i json-server -g

  • 运行服务
http://localhost:3001/todos

1.14 发送请求列表展示所有任务数据

  • 在Todo.jsx文件中导入axios
import axios from 'axios'
  • 在导入useEffect
import React, { useEffect } from 'react'
  • 调用函数,其内部完成ajax请求
//模拟ComponentDidMount
useEffect(() => {
    async function main() {
        try {
            let result = await axios.get('http://127.0.0.1:3001/todos')
            changetodos(result.data)
        } catch (e) {
            console.log('请求失败' + e.message)
        }
    }
    main();
}, [])

1.15 新增任务并发送ajax请求

  • 修改Todo.jsx中添加任务的方法代码为发送post请求
let addTodo = async (title) => {
    try {
        let result = await axios.post('http://127.0.0.1:3001/todos', {
            id: nanoid(),
            title,
            done: false
        })
        changetodos([
            ...todolists,
            result.data
        ])
    } catch (e) {
        console.warn('执行错误' + e.message)
    }
}

1.16 axios封装简化url-baseURL

  • 在src目录下新创建一个utils文件夹,并创建一个http.js文件
import axios from 'axios'
let instance = axios.create({
    baseURL: 'http://127.0.0.1:3001'
})
export default instance;
  • 修改Todo.jsx文件的导入以及请求的基础url
import axios from '../utils/http'
try {
    let result = await axios.post('/todos', {
        id: nanoid(),
        title,
        done: false
    })
    changetodos([
        ...todolists,
        result.data
    ])
} catch (e) {
    console.warn('执行错误' + e.message)
}
useEffect(() => {
    async function main() {
        try {
            let result = await axios.get('/todos')
            changetodos(result.data)
        } catch (e) {
            console.log('请求失败' + e.message)
        }
    }
    main();
}, [])

1.17 显示进度条效果

  • 安装进度条包
npm i nprogress
  • 考虑到每一个请求中都会用到进度条效果,所以我们可以给axios中添加拦截器,修改http.js代码
import axios from 'axios'
import NProgress from 'nprogress'
import "nprogress/nprogress.css"
let instance = axios.create({
    baseURL: 'http://127.0.0.1:3001'
})
instance.interceptors.request.use(config => {
    NProgress.start();
    return config;
})

instance.interceptors.response.use(response => {
    NProgress.done();
    return response;
})
export default instance;

1.18 错误的统一处理-中断Promise链条

  • 在axios的响应拦截器中添加失败响应回调
instance.interceptors.response.use(response => {
    NProgress.done();
    return response;
}, error => {
    console.log('请求响应失败')
    console.log(error)
    return new Promise(() => { });
})
  • 在发送axios请求时,可以省去try…catch代码

1.19 发送请求修改复选框选中状态以及删除

let modifyTodo = async (id, done) => {
    //注意:在这里咱们要修改状态时,在changetodos()里面需要传入一个修改状态后的新数组
    //React会将原数组以及修改状态后的新数组进行比较
    await axios.patch(`/todos/${id}`, { done })
    let newtodo = todolists.map(item => {
        if (item.id === id) {
            item.done = done;
        }
        return item;
    })
    changetodos(newtodo)
}
let removeTodo = async (id) => {
    await axios.delete(`/todos/${id}`)
    let newtodo = todolists.filter(item => item.id !== id);
    changetodos(newtodo)
}

1.20 批量更新状态与清空已完成任务

1.20.1 批量更新

let checkAllTodo = async (done) => {
    //批量更新状态
    let promises = todolists.map(item => {
        //发送请求
        return axios.patch(`/todos/${item.id}`, { done });
    })
    try {
        await Promise.all(promises);
        let newtodo = todolists.map(item => {
            item.done = done;
            return item;
        })
        changetodos(newtodo)
    } catch (e) {
        console.log('更新失败' + e.message);
    }
}

1.20.2 清空已完成任务

let removeAllTodo = async () => {
    //发送请求
    let promises = todolists.filter(item => item.done).map(item => {
        return axios.delete(`/todos/${item.id}`)
    })
    try {
        await Promise.all(promises);
        let newtodo = todolists.filter(item => !item.done);
        changetodos(newtodo)
    } catch (e) {
        console.log('删除失败' + e.message)
    }

}

1.21 toastify操作提醒

  • 安装
npm i toastify
  • 导入
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
  • 在需要提示的位置添加
  • 成功
toast.success('xxx');
  • 失败
toast.error('xxx');

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/688448.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高速电路设计系列分享-ADC电源的设计

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 提示&#xff1a;这里可以添加技术概要 如今&#xff0c;在设计人员面临众多电源选择的情况下&#xff0c;为高速ADC设计清洁电源时可能会面临巨大挑战。在利用高效开关电源而非传统LDO的场合&#xff0c;这尤其重要。…

liunx服务器使用selenium

文章目录 前言一、服务器下载google-chrome、chromedriver1、下载chrome2、下载chromedriver 二、安装Xvfb和python库pyvirtualdisplay、selenium1、安装Xvfb2、安装python库pyvirtualdisplay 三、配置好后测试总结 前言 最近在本地windows系统&#xff08;下面简称本地&#…

在线搭建K8S,kubernetes集群v1.23.9,docker支持的最后一个版本

1. 部署环境主机&#xff08;条件说明&#xff09; master 192.168.186.128 CentOS Linux release 7.9.2009 (Core) node1 192.168.186.129 CentOS Linux release 7.9.2009 (Core) node2 192.168.186.130 CentOS Linux release 7.9.2009 (Core)2. 系统初始化-所有节点&am…

探索MediaPipe的人像分割

MediaPipe是Google开源的计算机视觉处理框架&#xff0c;基于TensorFlow来训练模型。图像分割模块提供人像分割、头发分割、多类分割。本文主要探索如何实现人像分割&#xff0c;当然在人像分割基础上&#xff0c;我们可以做背景替换、背景模糊。 目录 一、配置参数与模型 1…

负载均衡 Load Balancing

负载均衡 Load Balancing 数据链路层负载均衡网络层负载均衡应用层负载均衡均衡策略与实现轮询与随机随机权重与加权轮询一致性 hash最少活跃数&#xff08;最少连接数&#xff09; 对于电商平台而言&#xff0c;随着业务的不断发展壮大&#xff0c;网站访问量和数据量也随之急…

什么是堆栈?c语言实现栈上的pop和push操作

什么是堆栈&#xff1f;c语言实现栈上pop和push操作的算法 堆栈&#xff08;stack&#xff09;实现栈上pop和push操作解释 堆栈&#xff08;stack&#xff09; 堆栈&#xff08;stack&#xff09;是一种数据结构&#xff0c;它具有后进先出&#xff08;Last-In-First-Out&…

抖音seo矩阵系统源码开发部署思路

抖音SEO矩阵系统源码开发和部署是一项复杂而又关键的任务。在开发阶段&#xff0c;我们需要根据抖音的搜索规则和算法&#xff0c;结合用户搜索意图和关键词&#xff0c;进行深入的研究和分析&#xff0c;以建立一个优秀的SEO矩阵系统。 在部署方面&#xff0c;我们需要遵循以…

完全零基础,如何学习渗透?

网络渗透这一行&#xff0c;做个脚本小子&#xff0c;使使工具啥的&#xff0c;个把月就学会了&#xff0c;这不难。 很多人把网络渗透简单的理解成就是搞网站&#xff0c;这是大错特错的&#xff01; 不过这也难怪&#xff0c;Web安全那三招两式&#xff0c;最好教也最好学&…

还在找wma格式怎么转换mp3?

在一个遥远的国度里&#xff0c;有一位名叫小芳的歌手&#xff0c;她声音甜美动人&#xff0c;深受人们的喜爱。然而&#xff0c;她的音乐制作团队告诉她&#xff0c;她的歌曲只能以wma格式发布。但是&#xff0c;她的粉丝们大多数使用的是mp3格式的音乐播放器&#xff0c;这让…

【Java】JVM(五)

垃圾回收机制 判断对象的存活 在堆里面存放着几乎所有的对象实例&#xff0c;垃圾回收器在对对进行回收前&#xff0c;要做的事情就是确定这些对象中哪些还是“存活”着&#xff0c;哪些已经“死去”&#xff08;死去代表着不可能再被任何途径使用得对象了&#xff09; 可达…

【pytest学习总结2.3】 - 如何使用固定装置fixtures(2)

目录 2.3.8 使用mark给固定装置传递数据 2.3.9 将固定装置工厂化 2.3.10 参数化固定装置 2.3.11 使用带有参数化固定装置的标记 2.3.12 使用来自固定装置功能中的固定装置 - 模块化 2.3.13 按固定装置实例自动分组测试 2.3.14 在类和模块中使用usefixtures 2.3.15 固定…

四.安防摄像机的WDR(HDR) 性能

四.安防摄像机的WDR(HDR) 性能 4.0 概述 WDR就是宽动态,wide dynamic range,或者HDR,high dynamic range,本质上是一回事,没任何区别。那么,到底什么是宽呢?很简单,搞不定的,就是太宽了,比如 摄像机装在室内,室内正常照度500lux,玻璃门外就是10000lux,室内外…

单机取证-鉴于信息安全管理与评估赛项-计算机单机取证特别说明-例题详解-Autopsy使用

芜湖~ 本期针对全国职业技能大赛-信息安全管理与评估赛项分析一下单机取证这个大项 并且取一例题 进行例题讲解 分享一些思路和逻辑 目录 题目 前言分析 .E01 ⽂件 DD 镜像和 E01 镜像的主要区别 如何打开和查看 E01 ⽂件扩展名&#xff1f; 常用工具使用-Autopsy 正…

现在这个年代,还有必要进行JVM调优吗?

导言 随着技术的不断发展&#xff0c;软件开发行业也在日新月异地进步。在过去的几十年里&#xff0c;Java语言和Java虚拟机&#xff08;JVM&#xff09;在开发企业级应用方面扮演了重要角色。然而&#xff0c;随着硬件和软件的进步&#xff0c;以及JVM本身的改进&#xff0c;…

Linux驱动学习(4) MTD字符驱动和块驱动1

系列文章目录 Linux驱动学习&#xff08;4&#xff09; 文章目录 目录 目录 系列文章目录 文章目录 前言 一、MTD是什么&#xff1f; 二、MTD子系统架构 1.Linux文件存储基本架构&#xff1a; ​ 2.MTD子系统基本架构&#xff1a; 总结 前言 MTD设备在嵌入式设备中…

2023网安面试题164道(附答案)

最近有不少小伙伴跑来咨询&#xff1a; 想找网络安全工作&#xff0c;应该要怎么进行技术面试准备&#xff1f;工作不到 2 年&#xff0c;想跳槽看下机会&#xff0c;有没有相关的面试题呢&#xff1f; 为了更好地帮助大家高薪就业&#xff0c;今天就给大家分享两份网络安全工…

【pytest学习总结2.2 】- 如何在测试中编写断言?

目录 2.2 如何在测试中编写断言 2.2.1 assert 断言 2.2.2 断言预期的异常 2.2.3 断言预期警告 【后续内容更新】 2.2.4 断言上下文 2.2.5 为失败的断言定义您自己的解释 2.2.6 断言的详细内容 &#x1f381;更多干货 完整版文档下载方式&#xff1a; 2.2 如何在测试中…

C++ 哈希思想 unordered_set unordered_map

文章目录 哈希思想常用的哈希函数哈希冲突解决方案哈希代码实现&#xff08;C 源码&#xff09;unordered_set & unordered_map 容器**unordered_set & unordered_map模拟实现**&#xff08;C 源码&#xff09; 哈希思想 抽象感受哈希的优点 如果我现在抛出一个问题&a…

Python+OpenCV 实现图像位平面分层进行图像信息隐藏

引言 闲言&#xff1a;这篇博客回归了传统图像处理领域&#xff0c;主要是在研究生的数字图像处理课程上接触到了新的知识–图像位平面&#xff0c;觉得还挺有意思的&#xff0c;可以用来做信息隐藏&#xff0c;索性记录一下。因为拖延的缘故&#xff0c;到学期末才赶出来一篇&…

计算机毕业论文内容参考|基于Android的旅游攻略APP的设计与实现

文章目录 导文摘要:前言:绪论:1. 课题背景:2. 国内外现状与趋势:3. 课题内容:相关技术与方法介绍:系统分析:系统设计:系统实现系统测试总结与展望本文总结后续工作展望导文 计算机毕业论文内容参考|基于Android的旅游攻略APP的设计与实现 摘要: 本文基于Android平台…