更优雅的更新与删除
更新
不优雅版
const updateTag = (id: number, obj: { name: string }) => {
//获取要修改的tag的下标
const index = findTagIndex(id);
//深拷贝tags
//vue可以直接在原数据上修改,但react不支持这项功能,因为它认为数据不可变
const tagsClone = JSON.parse(JSON.stringify(tags))
//把tagsClone的第index个删掉,换成{id: id, name: obj.name}
tagsClone.splice(index, 1, {id: id, name: obj.name})
setTags(tagsClone)
}
复制代码
优雅版
const updateTag = (id: number, obj: { name: string }) => {
setTags(tags.map(tag => tag.id === id ? {id, name: obj.name} : tag));
}
复制代码
删除
不优雅版
const deleteTag = (id: number) => {
//获取要删除的tag的下标
const index = findTagIndex(id);
//深拷贝tags
//vue可以直接在原数据上修改,但react不支持这项功能,因为它认为数据不可变
const tagsClone = JSON.parse(JSON.stringify(tags))
//把tagsClone的第index个删掉
tagsClone.splice(index, 1)
setTags(tagsClone)
}
复制代码
优雅版
const deleteTag = (id: number) => {
setTags(tags.filter(tag => tag.id !== id))
}
复制代码
增加编辑页面回退功能
为了使icon可以点击,需要修改Icon组件,即自定义Icon需要继承SVG所有属性
问题在于,当使用 ...rest
时,如果rest里拥有className那就会覆盖原本的className,为了解决这个问题,需要添加组件
yarn add classnames
yarn add --dev @types/classnames
复制代码
注意:保持版本号一致
更新后的Icon代码:
import React from 'react';
import cs from 'classnames';
let importAll = (requireContext: __WebpackModuleApi.RequireContext) => requireContext.keys().forEach(requireContext);
try {importAll(require.context('icons', true, /\.svg$/));} catch (error) {console.log(error);}
type Props = {
name?: string
} & React.SVGAttributes<SVGElement>
const Icon = (props: Props) => {
const {name, children, className, ...rest} = props
return (
<svg className={cs('icon', className)} {...rest}>
{props.name && <use xlinkHref={'#' + props.name}/>}
</svg>
);
};
export default Icon;
复制代码
解决createId刷新后id重置问题
解决方法是记住最后一次的id值,下次直接从 localStorage
中读取
let id = parseInt(window.localStorage.getItem('idMax') || '0')
const createId = () => {
id += 1;
window.localStorage.setItem('idMax', id.toString())
return id;
}
export {createId}
复制代码
解决标签持久化问题
自定义useUpdate
页面第一次默认刷新后,当deps改变时进行fn()
import {useEffect, useRef} from "react";
const useUpdate = (fn: () => void, deps: any[]) => {
const count = useRef(0)
useEffect(() => {
count.current += 1;
})
useEffect(() => {
if (count.current > 1) {
fn()
}
}, deps);//这里必须是不可变数据
}
export {useUpdate}
复制代码
读取localStorage并新增
注意默认标签的使用方法,即当localStorage为空时设定默认标签
useEffect(() => {
let localTags = JSON.parse(window.localStorage.getItem('tags') || '[]')
if (localTags.length === 0) {
localTags = [
{id: createId(), name: '衣'},
{id: createId(), name: '食'},
{id: createId(), name: '住'},
{id: createId(), name: '行'}
]
}
setTags(localTags)
}, [])
useUpdate(() => {
window.localStorage.setItem('tags', JSON.stringify(tags))
}, [tags])//组件挂载时执行
复制代码
解决记账页面持久化问题
之前没有写点击ok后会发生什么,现在进行补充。在点击ok后,数据应该被存入localStorage中,即进行submit操作
const submit = () => {
addRecord(selected)
alert('保存成功')
setSelected(defaultFormdata)
}
复制代码
其中addRecord是自定义hook中的功能
import {useEffect, useState} from "react";
import {useUpdate} from "./useUpdate";
type newRecordItem = {
tagIds: number[]
note: string
category: '+' | '-'
amount: number
}
type RecordItem = newRecordItem & {
createdAt: string//格式为ISO 8601
}
const useRecords = () => {
const [records, setRecords] = useState<RecordItem[]>([]);
useEffect(() => {
setRecords(JSON.parse(window.localStorage.getItem('records') || '[]'))
}, [])
useUpdate(() => {
window.localStorage.setItem('records', JSON.stringify(records))
}, [records])
const addRecord = (newRecord: newRecordItem) => {
const record = {...newRecord, createdAt: (new Date()).toISOString()}
setRecords([...records, record])
}
return {records, addRecord,}
}
export {useRecords}
复制代码
小技巧:如果两种类型很像,想不重复代码,第一种方法是上面代码使用的
&
技巧,还可以把多的类型中的某几个删除,代码为type newRecordItem = Omit<RecordItem, 'createdAt' | 'updatedAt'>
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END