组件开发-数据流向
管控组件 UI 状态的数据,一般可以由内部控制,或者由父级控制。
举例有开发同学设计的组件,管控组件 UI 状态的数据,即来自于内部又来自于父级。即组件内部 watch
父级传递的数据,如果有变化,然后覆盖或合并到内部的数据中。
这样违背了单向数据流的原则,如果出现问题,不易追踪。也不易管理数据。
数据来源于父级
以 React Demo
为例。
子组件
const Child = ({ value, onChange }) => {
return <input value={value} onChange={(e) => onChange(e.target.value)} />;
};
export default Child;
父级组件
import { useState } from 'react';
import Child from './Child';
const Parent = () => {
const [value, setValue] = useState(0)
return <>
父级控制状态:{value}
<div>
<Child value={value} onChange={setValue} />
</div>
</>
}
export default Parent
组件内部管控数据
import { useState } from 'react';
const Child = ({ onChange: propsOnChange }) => {
const [value, setValue] = useState();
const onChange = (e) => {
const newV = e.target.value;
setValue(newV);
propsOnChange && propsOnChange(newV);
};
return <input value={value} onChange={onChange} />;
};
export default Child;
父级组件
import { useState } from 'react';
import Child from './Child';
const Parent = () => {
const [value, setValue] = useState()
return <>
组件控制状态:{value}
<div>
<Child onChange={setValue} />
</div>
</>
}
export default Parent
更复杂的场景
相对以上的场景,下面增添了其它的特性:
- 增加默认值 defaultValue
- 管控组件 UI 状态的数据,可以来自于父级或来自于内部
import { useState } from 'react';
const Child = ({
value: propsValue,
defaultValue,
onChange: propsOnChange,
}) => {
// 关于 defaultValue 需要注意的是,只消费一次
const [value, setValue] = useState(defaultValue || '');
const onChange = (e) => {
const newV = e.target.value;
// 如果数据来自于父级,则不更新 value
propsValue === undefined && setValue(newV);
propsOnChange && propsOnChange(newV);
};
const props = {
value: propsValue !== undefined ? propsValue : value,
onChange
}
return <input {...props} />;
};
export default Child;
父级组件
import { useState } from 'react';
import Child from './Child';
const Parent = () => {
const [value, setValue] = useState()
const [componentValue, setComponentValue] = useState()
const onChange = (e) => {
const newV = e.target.value;
setValue(newV);
propsOnChange && propsOnChange(newV);
};
return <>
父级控制状态:{value}
<div>
<Child value={value} onChange={setValue} />
</div>
组件控制状态:{componentValue}
<div>
<Child onChange={setComponentValue} />
</div>
</>
}
export default Parent