React18 函数组件的定义,并React16更规范
const X:React.FunctionComponent = () => {
return (
<div></div>
);
}
或者
const X:React.FC = () => {
return (
<div></div>
);
}
想用props.children
const TT: React.FC = (props) => {
return (<div>{props.children}</div>);
}
遇到报错
Property 'children' does not exist on type '{}'.
这是因为react 18 更严格,给props加上any类型,不报错
const TT: React.FC = (props: any) => {
return (<div>{props.children}</div>);
}
可是外部使用时,
return (
<TT>
<div>hi</div>
</TT>
);
还是报错,似乎不应该传一个children
Type '{ children: Element[]; }' has no properties in common with type 'IntrinsicAttributes'
谷歌得到:
It seems the problem comes from the react-18 update in how React.FC is typed, as doesn't include children anymore
这样改才行
const TT: React.FC<{ children: React.ReactNode }> = (props: any) => {
return (<div>{props.children}</div>);
}
或者
type Props = {
children?: React.ReactNode;
}
const TT: React.FC<Props> = (props: any) => {
return (<div>{props.children}</div>);
}
这个children在react16还是默认就带的,在react18中就要显示声明,
参考:stackoverflow.com/questions/7…
标签组件
这样写是错误的
const TagsSection: React.FunctionComponent<Props> = () => {
const [tags, setTags] = useState<string[]>(['衣', '食', '住', '行']);
return (
<Wrapper>
<ol>
{tags.map((tag) => {
<li key={tag}>{tag}</li>
})}
</ol>
<button>新增标签</button>
</Wrapper>
);
}
这样写才行
<ol>
{tags.map((tag) =>
<li key={tag}>{tag}</li>
)}
</ol>
或者这样写
<ol>
{tags.map((tag) => {
return <li key={tag}>{tag}</li>
})}
</ol>
一切都是因为标签中数组的遍历方法,箭头函数后年的大括号就不能要,要了除非加return返回
严格模式的一个问题
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
严格模式会导致函数组件执行两次,不用严格模式
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
usrRef的使用
const inputRef = useRef<HTMLInputElement>(null);,其中,类型HTMLInputElement是必须的
input,受控组件,非受控组件
受控组件的写法,通过value和onChange控制
const NotesSection: React.FunctionComponent<Props> = (props) => {
const [notes, setNotes] = useState('');
return (<Wrapper>
<label>
<span>备注</span>
<input type="text"
placeholder={"在这里添加备注"}
defaultValue={notes}
onBlur={(e) => {
setNotes(e.target.value);
}}
/>
</label>
</Wrapper>);
}
非受控组件的写法,通过defaultValue和onBlur获取组件的值
const NotesSection: React.FunctionComponent<Props> = (props) => {
const [notes, setNotes] = useState('');
const inputRef = useRef<HTMLInputElement>(null);
return (<Wrapper>
<label>
<span>备注</span>
<input type="text"
ref={inputRef}
placeholder={"在这里添加备注"}
defaultValue={notes}
onBlur={(e) => {
// setNotes(e.target.value);
if(inputRef && inputRef.current){
setNotes(inputRef.current.value);
}
}}
/>
</label>
</Wrapper>);
}
字符串联合类型
如('-'|'+')[]表示字符串局限于-或者+两个字符,注意,是|
const [categoryList, setCategoryList] = useState<('-'|'+')[]>(['-', '+']);
完整代码如下
const CategorySection: React.FunctionComponent<Props> = () => {
const categoryMap = { '-': '支出', '+': '收入' }
const [category, setCategory] = useState<(keyof typeof categoryMap)>('-'); // 保存当前状态的
const [categoryList, setCategoryList] = useState<(keyof typeof categoryMap)[]>(['-', '+']);
return (<Wrapper>
<ul>
{categoryList.map((c) =>
<li key={c}
className={category == c ? "selected" : ""}
onClick={() => {
setCategory(c);
}}>{categoryMap[c]}
</li>)}
</ul>
</Wrapper>);
}
其他
- 淘宝橙:
#f60 - React和HTML的
onChange事件是不一样的,HTML的onChange会再鼠标移走、onBlur之前的时候触发,而HTML的onChange会在输入一个字符时触发 - 数组删除最后一个字符
outPut.slice(0,-1) - 部分类型
Partial
const [selected, setSelected] = useState({
tags: [] as string[],
note: '',
category: '-' as Category,
amount: 0
});
const onChange = (obj: Partial<typeof selected>) => {
setSelected({
...selected,
...obj
});
}