父子组件传递方法或值时,子组件负责暴露和接收,父组件负责调用和传递。因此,接触到最多的就是 ref 、useImperativeHandle()和props。
总结公式
- 子调父值
子收变量名={父变量名}- 子组件以
子收变量名={父变量名}定义属性,传值给子组件。子组件以 props 来接收,使用props.子收变量名获取变量值。
- 子调父方法
子收方法名={父方法名}- 子组件以
子收方法名={父方法名}定义属性,传值给子组件。子组件以 props 来接收,使用props.子收方法名()调用方法。
- 父调子值
useImperativeHandle(ref,()=>({变量}))- 子组件使用
useImperativeHandle(ref,()=>({变量}))暴露变量。父组件在子组件处定义ref={xxRef}, 使用xxRef.current.变量获取变量值。
- 父调子方法
useImperativeHandle(ref,()=>({方法名}))- 子组件使用
useImperativeHandle(ref,()=>({方法名}))暴露方法。父组件在子组件处定义ref={xxRef}, 使用xxRef.current.方法名()调用方法。
接下来开始实践吧~
父组件调用子组件的值
需要在同一个文件夹下创建 ParentCom.jsx 和 SonCom.jsx 两个文件,分别代表父组件和子组件。
父组件
import SonCom from './SonCom.jsx';
import React from 'react';
const ParentCom = () => {
const ref = React.useRef(null);
const [saveData, setSaveData] = React.useState(null); // 用来存储子组件的值
return (
<div style={{ border: '2px solid #7c7c', padding: 10, width: '580px', height: '200px' }}>
<span style={{ fontWeight: 'bold' }}>{`Parent ===> 绿色框内是父组件`}</span>
<br />
<div>
<span>来自子组件:</span>
{saveData}
<button
onClick={() => {
const dataFormSon = ref.current?.sonData?.name; // 调用子组件的值
setSaveData(dataFormSon); // 存储并展示
}}
>
获取数据
</button>
<button
onClick={() => {
setSaveData(null);
}}
>
清空
</button>
</div>
<SonCom ref={ref} />
</div>
);
};
export default ParentCom;
子组件
通过使用 useImperativeHandle() 暴露数据
import React from 'react';
const SonCom = React.forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({ sonData }), []); // 暴露给父组件
const sonData = { name: 'here is from son.' }; // 子组件的值
return (
<div style={{ border: '2px solid #7c7ced', padding: 10, width: '480px', height: '100px', marginTop: 10 }}>
<span style={{ fontWeight: 'bold' }}>{`Son ===> 紫色框内是子组件`}</span>
<br />
</div>
);
});
export default SonCom;
子组件调用父组件的值
需要在同一个文件夹下创建 ParentCom.jsx 和 SonCom.jsx 两个文件,分别代表父组件和子组件。
父组件
只需要在子组件上将需要传的值(或方法)作为属性传递即可。
import SonCom from './SonCom.jsx';
import React from 'react';
const ParentCom = () => {
const parentData = { name: 'here is from parent.' };
return (
<div style={{ border: '2px solid #7c7c', padding: 10, width: '580px', height: '200px' }}>
<span style={{ fontWeight: 'bold' }}>{`Parent ===> 绿色框内是父组件`}</span>
<br />
<SonCom parentData={parentData} />
</div>
);
};
export default ParentCom;
子组件
import React from 'react';
const SonCom = React.forwardRef((props, ref) => {
const { parentData } = props;
return (
<div style={{ border: '2px solid #7c7ced', padding: 10, width: '480px', height: '100px', marginTop: 10 }}>
<span style={{ fontWeight: 'bold' }}>{`Son ===> 紫色框内是子组件`}</span>
<br />
<div>
<span>来自父组件:</span>
{parentData?.name}
</div>
</div>
);
});
export default SonCom;
父组件调用子组件方法
需要在同一个文件夹下创建 ParentCom.jsx 和 SonCom.jsx 两个文件,分别代表父组件和子组件。
父组件
import SonCom from './SonCom.jsx';
import React from 'react';
const ParentCom = () => {
const ref = React.useRef(null);
return (
<div style={{ border: '2px solid #7c7c', padding: 10, width: '580px', height: '200px' }}>
<span style={{ fontWeight: 'bold' }}>{`Parent ===> 绿色框内是父组件`}</span>
<br />
<button
onClick={() => {
ref.current?.handleClick('你好,我是父组件'); // 调用子组件的方法
}}
>
点击子组件方法
</button>
<SonCom ref={ref}/>
</div>
);
};
export default ParentCom;
子组件
通过使用 useImperativeHandle() 暴露数据。
import React from 'react';
const SonCom = React.forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({ handleClick }), []); // 暴露给父组件
// 子组件的方法
const handleClick = (text) => {
alert(`子级组件方法: ${text}`);
};
return (
<div style={{ border: '2px solid #7c7ced', padding: 10, width: '480px', height: '100px', marginTop: 10 }}>
<span style={{ fontWeight: 'bold' }}>{`Son ===> 紫色框内是子组件`}</span>
<br />
</div>
);
});
export default SonCom;
子组件调用父组件方法
需要在同一个文件夹下创建 ParentCom.jsx 和 SonCom.jsx 两个文件,分别代表父组件和子组件。
父组件
只需要在子组件上将需要传的值(或方法)作为属性传递即可。
import SonCom from './SonCom.jsx';
import React from 'react';
const ParentCom = () => {
// 父组件的方法
const handleClick = (text) => {
alert(`父级组件方法: ${text}`);
};
return (
<div style={{ border: '2px solid #7c7c', padding: 10, width: '580px', height: '200px' }}>
<span style={{ fontWeight: 'bold' }}>{`Parent ===> 绿色框内是父组件`}</span>
<br />
<SonCom handleParentClick={handleClick} />
</div>
);
};
export default ParentCom;
子组件
import React from 'react';
const SonCom = React.forwardRef((props, ref) => {
const { handleParentClick } = props; // 接收来自父组件的方法
return (
<div style={{ border: '2px solid #7c7ced', padding: 10, width: '480px', height: '100px', marginTop: 10 }}>
<span style={{ fontWeight: 'bold' }}>{`Son ===> 紫色框内是子组件`}</span>
<br />
<button onClick={() => handleParentClick('你好,我是子组件')}>点击父级组件</button>
</div>
);
});
export default SonCom;
代码整合
以下是将父子组件代码全部整合到一起的效果,只在一个文件下完成(以.tsx为例),可以试试看效果~
注:若是
.jsx的,只需要把类型相关的代码去掉即可
import React, { useImperativeHandle, useState } from 'react';
type SonProps = {
handleParentClick: (text?: string) => void;
parentData?: string;
};
/**
* 子组件
* @returns
*/
const SonCom = React.forwardRef((props: SonProps, ref) => {
useImperativeHandle(ref, () => ({ handleSonClick, sonData }), []); // 暴露给父组件的方法和值
const sonData = { name: 'here is from son.' }; // // 子组件内部值
const [saveData, setSaveData] = useState(null);
const { handleParentClick, parentData } = props; // 接收来自父组件的方法和值
// 子组件内部方法
const handleSonClick = (text?: string) => {
// 一些逻辑
alert(`子级组件方法: ${text}`);
};
return (
<div style={{ border: '2px solid #7c7ced', padding: 10, width: '480px', height: '100px', marginTop: 10 }}>
<span style={{ fontWeight: 'bold' }}>{`Son ===> 紫色框内是子组件`}</span>
<br />
<button onClick={() => handleParentClick('你好,我是子组件')}>点击父级组件</button>
<div>
<span>来自父组件:</span>
{saveData}
<button
onClick={() => {
setSaveData(parentData?.name);
}}
>
获取数据
</button>
<button
onClick={() => {
setSaveData(null);
}}
>
清空
</button>
</div>
</div>
);
});
/**
* 父组件
* @returns
*/
const ParentCom = () => {
const ref = React.useRef(null);
const parentData = { name: 'here is from parent.' };
const [saveData, setSaveData] = useState(null);
const handleParentClick = (text?: string) => {
// 一些逻辑
alert(`父级组件方法: ${text}`);
};
return (
<div style={{ border: '2px solid #7c7c', padding: 10, width: '580px', height: '200px' }}>
<span style={{ fontWeight: 'bold' }}>{`Parent ===> 绿色框内是父组件`}</span>
<br />
<button
onClick={() => {
ref.current?.handleSonClick('你好,我是父组件');
}}
>
点击子组件方法
</button>
<div>
<span>来自子组件:</span>
{saveData}
<button
onClick={() => {
setSaveData(ref.current?.sonData?.name);
}}
>
获取数据
</button>
<button
onClick={() => {
setSaveData(null);
}}
>
清空
</button>
</div>
<SonCom ref={ref} handleParentClick={handleParentClick} parentData={parentData} />
</div>
);
};
export default ParentCom;