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全部屬性vue
問題在於,當使用 ...rest
時,若是rest裏擁有className那就會覆蓋本來的className,爲了解決這個問題,須要添加組件react
yarn add classnames
yarn add --dev @types/classnames
複製代碼
注意:保持版本號一致markdown
更新後的Icon代碼:svg
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;
複製代碼
解決方法是記住最後一次的id值,下次直接從 localStorage
中讀取ui
let id = parseInt(window.localStorage.getItem('idMax') || '0')
const createId = () => {
id += 1;
window.localStorage.setItem('idMax', id.toString())
return id;
}
export {createId}
複製代碼
頁面第一次默認刷新後,當deps改變時進行fn()spa
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爲空時設定默認標籤rest
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操做code
const submit = () => {
addRecord(selected)
alert('保存成功')
setSelected(defaultFormdata)
}
複製代碼
其中addRecord是自定義hook中的功能orm
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'>
繼承