前端系列(三)react获取子组件属性的方法

2021-10-29  本文已影响0人  onmeiei

组件组合有几种情况

组件布局

父组件不保存任何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方法的日志,看出两种方案的区别。

上一篇 下一篇

猜你喜欢

热点阅读