irpas技术客

【Typescript学习】使用 React 和 TypeScript 构建web应用(三)所有组件_咕咕酱没有悲伤

irpas 6761

教程来自freecodeCamp:【英字】使用 React 和 TypeScript 构建应用程序 跟做,仅记录用 其他资料:https://·/free-photo/crumpled-yellow-paper-background-close-up_60487-2390.jpg?size=626&ext=jpg"); } .todos__single--text { flex: 1; padding: 5px; border: none; font-size: 20px; } .todos__single--textJ:focus { outline: none; } .icon { margin-left: 10px; font-size: 25px; cursor: pointer; } /* 响应式布局 */ @media (max-width: 1200px) { .todos__single { width: 40%; } } @media (max-width: 700px) { .input { width: 95%; } .todos { width: 95%; } .todos__single { width: 100%; } }

其中响应式布局的效果如下,当宽度小于700px时:

3 todo的按钮响应函数

分别对三个按钮实现功能,较简单的是点击完成(done)的事件响应和删除(delete)的事件响应 SingleTodo.tsx

// done按钮的响应 const handleDone = (id: number) => { // 改变对应todo的isDone属性 setTodos( todos.map((todo) => todo.id === id ? {...todo, isDone: !todo.isDone} : todo ) ); }; // delete按钮的响应 const handleDelete = (id: number ) => { setTodos( todos.filter((todo) => todo.id === id) ) }; return ( <form className='todos__single'> {// 如果是完成状态,则用删除线效果 todo.isDone ? ( // <s> 删除线标签 <s className="todos__single--text">{todo.todo}</s> ):( <span className="todos__single--text">{todo.todo}</span> )} <div> <span className="icon"><AiFillEdit/></span> <span className="icon" onClick={()=>handleDelete(todo.id)}><AiFillDelete/></span> <span className="icon" onClick={()=>handleDone(todo.id)}><MdDone/></span> </div> </form> )

点击edit按钮的事件响应逻辑比较复杂

我们需要一个状态变量edit,跟踪当前是否处于“编辑状态”;以及一个状态变量editTodo,跟踪当前输入到todo的文本。 const [edit, setEdit] = useState<boolean>(false); const [editTodo, setEditTodo] = useState<string>(todo.todo); 在结构里添加显示的逻辑和编辑完成后提交时的事件 <form className='todos__single' onSubmit={(e)=>handleEdit(e, todo.id)}> { // 如果是edit状态,则显示input框,否则是todo的描述 edit ? ( <input value={editTodo} onChange={(e)=> setEditTodo(e.target.value)} className='todos__single--text' /> ) : ( // 如果是完成状态,则用删除线效果 todo.isDone ? ( // s 下划线标签 <s className="todos__single--text">{todo.todo}</s> ):( <span className="todos__single--text">{todo.todo}</span> ) ) } ... </form> 处理handleEdit函数 const handleEdit = (e:React.FormEvent, id: number) => { e.preventDefault(); // 禁止默认的页面刷新行为 setTodos(todos.map((todo => ( todo.id === id? {...todo, todo: editTodo}:todo ) ))) setEdit(false); } 我们需要点击edit按钮时,input框自动获得焦点,因此用useRef挂载到input框上,同时使用对edit变量的useEffect const inputRef = useRef<HTMLInputElement>(null); useEffect(() => { inputRef.current?.focus(); }, [edit]);

第三天done! 今天新建了TodoList组件和SingleTodo组件,完成了相应的UI和大部分的逻辑。 UI中需要注意适应窗口的响应式布局、如何使用react-icons框架;组件实现中需要注意具体的逻辑、状态变量如何切换

TodoList.tsx

import React from 'react' import './styles.css' import { Todo } from "../model"; import SingleTodo from './SingleTodo'; type Props = { todos: Todo[], setTodos: React.Dispatch<React.SetStateAction<Todo[]>>, } const TodoList:React.FC<Props> = ({todos, setTodos}: Props) => { return ( <div className='todos'> {todos.map(todo =>( <SingleTodo key={todo.id} todo={todo} todos={todos} setTodos={setTodos}/> ))} </div> ) } export default TodoList

SingleTodo.tsx

import React, { useState, useRef, useEffect } from 'react' import { Todo } from "../model"; import { AiFillEdit, AiFillDelete } from "react-icons/ai"; import { MdDone } from "react-icons/md"; import './styles.css' type Props = { todo: Todo, todos: Todo[], setTodos: React.Dispatch<React.SetStateAction<Todo[]>>, } const SingleTodo = ({todo, todos, setTodos}: Props) => { const [edit, setEdit] = useState<boolean>(false); const [editTodo, setEditTodo] = useState<string>(todo.todo); // done按钮的响应 const handleDone = (id: number) => { // 改变对应todo的isDone属性 setTodos( todos.map((todo) => todo.id === id ? {...todo, isDone: !todo.isDone} : todo ) ); }; // edit按钮的响应 const handleEdit = (e:React.FormEvent, id: number) => { e.preventDefault(); // 禁止默认的页面刷新行为 setTodos(todos.map((todo => ( todo.id === id? {...todo, todo: editTodo}:todo ) ))) setEdit(false); } // delete按钮的响应 const handleDelete = (id: number ) => { setTodos( todos.filter((todo) => todo.id === id) ) }; const inputRef = useRef<HTMLInputElement>(null); // 编辑框 // edit状态改变时自动获取编辑框的焦点 useEffect(() => { inputRef.current?.focus(); }, [edit]); return ( <form className='todos__single' onSubmit={(e)=>handleEdit(e, todo.id)}> { // 如果是edit状态,则显示input框,否则是todo的描述 edit ? ( <input ref={inputRef} value={editTodo} onChange={(e)=> setEditTodo(e.target.value)} className='todos__single--text' /> ) : ( // 如果是完成状态,则用删除线效果 todo.isDone ? ( // s 下划线标签 <s className="todos__single--text">{todo.todo}</s> ):( <span className="todos__single--text">{todo.todo}</span> ) ) } <div> <span className="icon" onClick={()=>{ if(!edit && !todo.isDone){ setEdit(!edit); // edit变为true } }}><AiFillEdit/></span> <span className="icon" onClick={()=>handleDelete(todo.id)}><AiFillDelete/></span> <span className="icon" onClick={()=>handleDone(todo.id)}><MdDone/></span> </div> </form> ) } export default SingleTodo

明天要使用react reducer hook进行状态管理了,可以先复习一下

使用到的:

react的按钮UI组件react-icons响应式布局


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #Typescript学习使用 #React # #Typescript #构建web应用三所有组件