前端系列(三)react获取子组件属性的方法
2021-10-29 本文已影响0人
onmeiei
组件组合有几种情况
- 父组件不保存任何state,子组件A和子组件B各自保存state
- 父组件保存state,子组件A和子组件B不保存state,数据由父组件维护
![](https://img.haomeiwen.com/i15383821/364709b12519f987.png)
父组件不保存任何state,子组件A和子组件B各自保存state
这种情况,如果需要在父组件进行RESTful调用时,需要子组件A和子组件B提供操作数据的方法(主要是初始化和数据获取)
需要使用forwardRef来实现,具体做法如下(以FC为例)
const EcParent: React.FC = () => {
const childRefA = React.createRef<EcRef<EcChildBean>>()
const childRefB = React.createRef<EcRef<EcChildBean>>()
return <>
<EcChild bean={{ username: "A", age: 1 }} ref={childRefA} />
<EcChild bean={{ username: "B", age: 2 }} ref={childRefB} />
<button onClick={() => {
console.info(JSON.stringify(childRefA.current?.get()))
console.info(JSON.stringify(childRefB.current?.get()))
}} >click</button>
</>
}
export { EcParent }
const EcChild = React.forwardRef<EcRef<EcChildBean>, EcProps<EcChildBean>>((props, ref) => {
const [username, setUsername] = useState<string>(props.bean?.username || "")
const [age, setAge] = useState<number>(props.bean?.age || 10)
useEffect(() => {
console.log("hello, props, child ===> ", JSON.stringify(props))
}, [props])
useImperativeHandle(ref, createEcRef<EcChildBean>(() => {
return {
username: username,
age: age,
}
}))
return <div>
<label htmlFor={"username"}>UserName: </label>
<input id="username" value={username} type="text" onChange={evt => setUsername(evt.target.value)} />
<label htmlFor={"age"}>Age: </label>
<input id="age" value={age} type="number" onChange={evt => setAge(parseInt(evt.target.value))} />
</div>
})
export default EcChild
export type { EcChildBean }
使用场景,A和B不需要进行通讯,但是与服务器进行RESTful通讯时,需要同时获取A和B的数据。
这样做可以避免操作A的数据时,刷新B的数据。
父组件保存state,子组件A和子组件B不保存state,数据由父组件维护
这种情况,如果需要在父组件进行RESTful调用时,可以直接使用父组件维护的数据进行处理。
缺点是,每次子组件操作数据,由于操作的都是父组件的state,会导致父组件的所有子组件进行刷新。如果组件数量特别多,性能较上一个方案差一些
const EcParent: React.FC = () => {
const [childA, setChildA] = useState<EcChildBean>({ username: "A", age: 1 })
const [childB, setChildB] = useState<EcChildBean>({ username: "B", age: 2 })
return <>
<EcChild bean={childA} onChange={a => setChildA(a)} />
<EcChild bean={childB} onChange={b => setChildB(b)} />
<button onClick={() => {
console.info(JSON.stringify(childA))
console.info(JSON.stringify(childB))
}} >click</button>
</>
}
export { EcParent }
interface EcChildBean {
username: string
age: number
}
const EcChild: React.FC<EcProps<EcChildBean>> = (props) => {
useEffect(() => {
console.log("hello, props, child ===> ", JSON.stringify(props))
}, [props])
return <div>
<label htmlFor={"username"}>UserName: </label>
<input id="username" value={props.bean?.username} type="text" onChange={evt => props.onChange({ ...props.bean, username: evt.target.value })} />
<label htmlFor={"age"}>Age: </label>
<input id="age" value={props.bean?.age} type="number" onChange={evt => props.onChange({ ...props.bean, age: parseInt(evt.target.value) })} />
</div>
}
export default EcChild
export type { EcChildBean }
源码已经上传到了Ocean/reactjs-comm-demo (gitee.com)
可以通过console中打印的useEffect方法的日志,看出两种方案的区别。