受控和非受控 input
// 受控
const NotePart: React.FC = () => {
const note = props.value;
const onChange: ChangeEventHandler<HTMLInputElement> = (e) => {
props.onChange(e.target.value);
return (
<Wrapper>
<div>备注:<input value={note} onChange={(e) => setNote(e.target.value)} type="text" placeholder="请输入备注"/></div>
</Wrapper>
);
};
// 非受控
const NotePart: React.FC = (props) => {
const [note, setNote] = useState('');
const refInput = useRef<HTMLInputElement>(null);
const onBlur = () => {
if (refInput.current !== null) {
setNote(refInput.current.value);
}
};
return (
<Wrapper>
<div>备注:<input ref={refInput} defaultValue={note} onBlur={onBlur} type="text" placeholder="请输入备注"/></div>
</Wrapper>
);
};
实现爷爷组件读取操作孙子组件
爷爷组件
const [selected, setSelected] = useState({
tags: [] as number[],
note: '',
category: '-' as Category,
amount: '0'
});
const onChange = (obj: Partial<typeof selected>) => {
setSelected({
...selected,
...obj
});
};
return (
<LayoutWrapper>
{selected.tags}
--
{selected.note}
--
{selected.category}
--
{selected.amount}
<HeaderSection value={selected.tags} onChange={(tags) => {onChange({tags});}}/>
<RecordsSection
note={selected.note} onChangeNote={(note) => {onChange({note});}}
category={selected.category} onChangeCategory={(category) => {onChange({category});}}
amount={selected.amount} onChangeAmount={(amount) => {onChange({amount});}}
/>
</LayoutWrapper>
);
}
父亲组件
type Props = {
note: string,
category: '-' | '+',
amount: string,
onChangeNote: (note: string) => void
onChangeAmount: (amount: string) => void
onChangeCategory: (category: '-' | '+') => void
}
const RecordsSection: React.FC<Props> = (props) => {
let history = useHistory();
const submit = () => {
alert('保存成功');
history.push('/');
};
return (
<Wrapper>
<SelectionPart {...props}/>
<NotePart {...props}/>
<NumberPadPart{...props}/>
</Wrapper>
);
};
export default RecordsSection;
孙子组件
SelectionPart 组件 使用
// SelectionPart 组件
type Props = {
category: '-' | '+',
onChangeCategory: (category: '-' | '+') => void
}
const SelectionPart: React.FC<Props> = (props) => {
const categoryMap = {'-': '支出', '+': '收入'};
type keys = keyof typeof categoryMap
const [categoryList] = useState<keys[]>(['-', '+']);
const category = props.category;
return (
<Wrapper>
{categoryList.map((c, index) =>
<div className={category === c ? 'selected' : ''} onClick={() => {props.onChangeCategory(c);}} key={index}>
{categoryMap[c]}
</div>
)}
</Wrapper>
);
};
export default SelectionPart;
NotePart组件使用
// NotePart组件
type Props = {
note: string,
onChangeNote: (value: string) => void
}
const NotePart: React.FC<Props> = (props) => {
const {note} = props;
const refInput = useRef<HTMLInputElement>(null);
const onBlur = () => {
if (refInput.current !== null) {
props.onChangeNote(refInput.current.value);
}
};
return (
<Wrapper>
<div>备注:<input ref={refInput} defaultValue={note} onBlur={onBlur} type="text" placeholder="请输入备注"/></div>
</Wrapper>
);
};
export default NotePart;
NumberPadPart 组件使用
// NumberPadPart组件
type Props = {
amount: string,
onChangeAmount: (amount: string) => void
}
const NumberPadPart: React.FC<Props> = (props) => {
const [output, _setOutput] = useState<string>('0');
const setOutput = (output: string) => {
if (output.length > 16) {
output = output.slice(0, 16);
} else if (output.length === 0) {
output = '0';
}
_setOutput(output);
props.onChangeAmount(output);
};
......