受控和非受控 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});}}/><RecordsSectionnote={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) => voidonChangeAmount: (amount: string) => voidonChangeCategory: (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 categoryMapconst [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);};......
