实战!增删改查的不平凡

简介: 结合 React 哲学 中的思想,我们可以很自然的想到该按钮中的数据有:// 任务列表const [jobs, setJobs] = useState<Array<Job>>([])// 编辑窗口显示与否const [show, setShow] = useState(false)// 每次输入时当前任务描述const [desc, setDesc] = useState('')单个任务的数据格式为interface Job { desc: string, id: string, createTime: number, isSelected: boolean}

微信图片_20220511163416.png


学习了 useState 与 useRef ,结合前面几章内容,我们可以实现一个非常经典的功能:任务列表。


当我点击新增时,编辑弹窗出现,输入框自动获得焦点


微信图片_20220511163422.png


输入任务描述之后,点击创建,此时任务创建成功,编辑弹窗消失,新增按钮再次出现


微信图片_20220511163426.png


结合 React 哲学 中的思想,我们可以很自然的想到该按钮中的数据有:


// 任务列表
const [jobs, setJobs] = useState<Array<Job>>([])
// 编辑窗口显示与否
const [show, setShow] = useState(false)
// 每次输入时当前任务描述
const [desc, setDesc] = useState('')


单个任务的数据格式为


interface Job {
  desc: string,
  id: string,
  createTime: number,
  isSelected: boolean
}


点击「新增按钮」,编辑弹窗出现,新增按钮消失,因此在 JSX 中,我们可以这样去表达他们的交互关系


{show ? (
  <div className="dialog">
    <input
      onChange={event => setDesc(event.target.value)}
      ref={inputRef}
      placeholder="请输入任务描述"
      onBlur={() => { setTimeout(() => { setShow(false) }, 0) }}
    />
    <div className="create" onClick={add}>创建</div>
  </div>
) : <div className="add" onClick={() => setShow(true)}>新增</div>}


input 框在失去焦点后编辑弹窗消失


我们可以使用 useRef  获得 input 组件的引用,以实现弹窗出现之后 input 能自动获取焦点的效果


const inputRef = useRef<HTMLInputElement>(null)


但是需要注意的是,input 元素是在 show 变成 true ,并且组件真实 DOM 再次渲染完成之后才能获取引用,因此这里运用了一个之后会学习的知识来解决这个问题


useEffect(() => {
// show 变成 true,并且组件渲染完成之后执行
  if (show) {
    inputRef.current?.focus()
  }
}, [show])


当编辑弹窗出现,我们在弹窗中输入内容,需要将输入内容保存在 desc 字段中。


基于只操作数据的思想,点击新增,其实只是往任务列表数据 jobs 中新增一个值


function add() {
  jobs.push({
    id: randomId(),
    desc,
    isSelected: false,
    createTime: Date.now()
  })
  setJobs([...jobs])
  setDesc('')
}


这里需要注意为了让 React 感知到你的数组发生了变化,需要重新创建一个新的引用数组。否则 React 无法识别。


jobs 表示任务列表,可以根据该数据遍历出整个列表


{jobs.map((job, i) => (
  <div className="job-wrapper" key={job.id}>
    <div className="selected" onClick={() => troggleSelected(i)}>
      {job.isSelected && <div className="circle"></div>}
    </div>
    <div className="desc">{job.desc}</div>
    <div className="remove" onClick={() => remove(i)}>删除</div>
  </div>
))}


删除与编辑都只需要修改对应的数组数据即可


function remove(i: number) {
  jobs.splice(i, 1)
  setJobs([...jobs])
}
function troggleSelected(i: number) {
  jobs[i].isSelected = !jobs[i].isSelected
  setJobs([...jobs])
}


就这样,我们轻松实现了一个列表的增删改查,完整代码如下


import { useEffect, useRef, useState } from 'react';
import { randomId } from './utils/index'
import logo from './logo.svg';
import './App.css';
interface Job {
  desc: string,
  id: string,
  createTime: number,
  isSelected: boolean
}
function App() {
  const [jobs, setJobs] = useState<Array<Job>>([])
  const [show, setShow] = useState(false)
  const [desc, setDesc] = useState('')
  const inputRef = useRef<HTMLInputElement>(null)
  useEffect(() => {
    if (show) {
      inputRef.current?.focus()
    }
  }, [show])
  function add() {
    jobs.push({
      id: randomId(),
      desc,
      isSelected: false,
      createTime: Date.now()
    })
    setJobs([...jobs])
    setDesc('')
  }
  function remove(i: number) {
    jobs.splice(i, 1)
    setJobs([...jobs])
  }
  function troggleSelected(i: number) {
    jobs[i].isSelected = !jobs[i].isSelected
    setJobs([...jobs])
  }
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <h1>React 知命境</h1>
      </header>
      <div className="container">
        <div className="task-header">
          <div className="title">进行中的任务</div>
          <div className="right">...</div>
        </div>
        {jobs.map((job, i) => (
          <div className="job-wrapper" key={job.id}>
            <div className="selected" onClick={() => troggleSelected(i)}>
              {job.isSelected && <div className="circle"></div>}
            </div>
            <div className="desc">{job.desc}</div>
            <div className="remove" onClick={() => remove(i)}>删除</div>
          </div>
        ))}
        {show ? (
          <div className="dialog">
            <input
              onChange={event => setDesc(event.target.value)}
              ref={inputRef}
              placeholder="请输入任务描述"
              onBlur={() => { setTimeout(() => { setShow(false) }, 0) }}
            />
            <div className="create" onClick={add}>创建</div>
          </div>
        ) : <div className="add" onClick={() => setShow(true)}>新增</div>}
      </div>
    </div>
  );
}
export default App;


微信图片_20220511163430.png

很显然,代码功能虽然实现了,但是代码上并不简洁,学习了 React 哲学的同学可以思考一下,我们应该从哪些角度去思考如何进一步简化代码呢?

相关文章
|
3天前
|
SQL 数据库
Spring5入门到实战------13、使用JdbcTemplate操作数据库(批量增删改)。具体代码+讲解 【下篇】
这篇文章是Spring5框架的实战教程,深入讲解了如何使用JdbcTemplate进行数据库的批量操作,包括批量添加、批量修改和批量删除的具体代码实现和测试过程,并通过完整的项目案例展示了如何在实际开发中应用这些技术。
Spring5入门到实战------13、使用JdbcTemplate操作数据库(批量增删改)。具体代码+讲解 【下篇】
|
3天前
|
SQL 数据库连接 API
ThinkPHP6实现增删改查接口
ThinkPHP6实现增删改查接口
11 1
|
3天前
|
XML 数据库 数据格式
Spring5入门到实战------14、完全注解开发形式 ----JdbcTemplate操作数据库(增删改查、批量增删改)。具体代码+讲解 【终结篇】
这篇文章是Spring5框架的实战教程的终结篇,介绍了如何使用注解而非XML配置文件来实现JdbcTemplate的数据库操作,包括增删改查和批量操作,通过创建配置类来注入数据库连接池和JdbcTemplate对象,并展示了完全注解开发形式的项目结构和代码实现。
Spring5入门到实战------14、完全注解开发形式 ----JdbcTemplate操作数据库(增删改查、批量增删改)。具体代码+讲解 【终结篇】
|
3天前
|
SQL XML Java
Spring5入门到实战------12、使用JdbcTemplate操作数据库(增删改查)。具体代码+讲解 【上篇】
这篇文章是Spring5框架的实战教程,详细讲解了如何使用JdbcTemplate进行数据库的增删改查操作,包括在项目中引入依赖、配置数据库连接池、创建实体类、定义DAO接口及其实现,并提供了具体的代码示例和测试结果,最后还提供了完整的XML配置文件和测试代码。
Spring5入门到实战------12、使用JdbcTemplate操作数据库(增删改查)。具体代码+讲解 【上篇】
|
7天前
|
存储 缓存 运维
优化高并发环境下的数据库查询性能:实战经验与技巧
在高并发环境下,数据库性能往往成为系统瓶颈。本文将深入探讨在高并发场景下优化数据库查询性能的策略与实践,包括索引优化、查询优化、数据库架构设计以及缓存机制的应用。通过对具体案例的分析,读者将能够掌握提升数据库性能的关键技术,从而在面对大规模用户请求时提高系统的响应速度和稳定性。
|
4天前
|
druid Java 数据库连接
SpringBoot项目整合MybatisPlus持久层框架+Druid数据库连接池,以及实现增删改查功能
SpringBoot项目整合MybatisPlus和Druid数据库连接池,实现基本的增删改查功能。
15 0
|
4天前
|
前端开发 Java 关系型数据库
通过HTML网页对mysql数据库进行增删改查(CRUD实例)
通过HTML网页对mysql数据库进行增删改查(CRUD实例)
|
5天前
|
存储 关系型数据库 MySQL
MySQL——数据库备份上传到阿里云OSS存储
MySQL——数据库备份上传到阿里云OSS存储
18 0
|
5天前
|
缓存 NoSQL Redis
一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这篇文章是关于Java面试中可能会遇到的五个问题,包括MySQL索引类型及其对数据库性能的影响、Redis的RDB和AOF持久化机制、Redis的过期键删除策略、Redis的单线程模型为何高效,以及缓存雪崩、缓存穿透和缓存击穿的概念及其解决方案。