什么是组件?
一个组件就是用户界面的一部分,它可以有自己的逻辑和外观。
组件之间可以互相嵌套,也可以复用多次
为什么要用组件?
组件能让开发者像搭积木一样快速构建一个完整的庞大应用,大大提升了开发效率,降低了维护成本,因此当下前端的主流开发模式即组件化开发
定义组件
react 中的组件有以下特征:
- 是一个首字母大写的函数
- 函数的返回值是一段 JSX 代码,用于渲染页面
- 通常每个组件都用独立的
.jsx
文件描述,并用export default
对外导出 - return 返回的语句写在一行,则可以省略() ,但只要不在一行,就必须要 () ,所以建议总是加上 ()
return <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />;
范例 Demo.jsx
function Demo() { return <div>你好</div>; } export default Demo;
也可以写成箭头函数
const Demo = () => { return <div>你好</div>; }; export default Demo;
使用组件
以在 App.jsx 中使用为例:
先导入
import Demo from './Demo.js';
使用
function App() { return ( <> <Demo /> </> ); }
可以单标签自闭,也可以像 html 一样双标签配对
<Demo></Demo>
组件通信
即组件间相互传递数据
父组件传值给子组件
<Avatar person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }} size={100} />
子组件获取父组件的传值 props
function Avatar({ person, size }) { // 直接访问 person 和 size 即可 }
或
function Avatar(props) { let person = props.person; let size = props.size; }
指定 props 的默认值
function Avatar({ person, size = 100 }) { }
给 props 添加类型校验 propTypes
PropTypes
是 React 提供的一个用于类型检查的库。它可以用来验证组件的属性(props)是否符合预期的类型和格式
import PropTypes from "prop-types";
写在组件函数外
Avatar.propTypes = { person: PropTypes.object, size: PropTypes.number, };
添加必填校验 .isRequired
在末尾添加 .isRequired
Avatar.propTypes = { person: PropTypes.object.isRequired, size: PropTypes.number, };
数据类型检查器
- PropTypes.string
- PropTypes.symbol
- PropTypes.number
- PropTypes.bigint
- PropTypes.bool
- PropTypes.func
- PropTypes.array
- PropTypes.object
节点类型检查器
- PropTypes.node
- PropTypes.element
- PropTypes.elementType
父组件给子组件传递 JSX 内容(插槽) children
使用子组件时,其标签内的内容(即插槽),在子组件中可通过 children 获取到
父组件
import Child from "./child.jsx"; function Father() { return ( <> <Child>你好</Child> </> ); } export default Father;
子组件
function Child({ children }) { return ( <> <h1>我是子组件</h1> <div>父组件传入的插槽内容为:{children}</div> </> ); } export default Child;
模拟 vue 的具名插槽
详见 https://blog.csdn.net/weixin_41192489/article/details/139835331
子组件传值给父组件
实现方案:在子组件中调用父组件中的函数并传递参数
父组件
import { useState } from "react"; import Child from "./child.jsx"; function Father() { const [name, setName] = useState("朝阳"); function changeName() { setName("新的朝阳"); } return ( <> <h1>我是父组件</h1> <p>父组件中的变量 name 的值为:{name}</p> <Child changeName={changeName}></Child> </> ); } export default Father;
子组件
import PropTypes from "prop-types"; function Child({ changeName }) { return ( <> <h1>我是子组件</h1> <button onClick={changeName}>修改父组件的名字为“新的朝阳”</button> </> ); } Child.propTypes = { changeName: PropTypes.func, }; export default Child;
兄弟组件通信
father.jsx
import { useState } from "react"; import ChildA from "./childA.jsx"; import ChildB from "./childB.jsx"; function Father() { const [msgA, setMsgA] = useState(""); function sendMsgToB(msg) { setMsgA(msg); } return ( <> <ChildA sendMsgToB={sendMsgToB} /> <ChildB msgA={msgA} /> </> ); } export default Father;
childA.jsx
import PropTypes from "prop-types"; function ChildA({ sendMsgToB }) { const dataA = "子组件A的数据"; return ( <> <div> <h1>我是子组件A</h1> <button onClick={() => sendMsgToB(dataA)}>向子组件B传递数据</button> </div> </> ); } ChildA.propTypes = { sendMsgToB: PropTypes.func, }; export default ChildA;
childB.jsx
import PropTypes from "prop-types"; function ChildB({ msgA }) { return ( <> <div> <h1>我是子组件B</h1> <p>子组件A传来的数据为:{msgA}</p> </div> </> ); } ChildB.propTypes = { msgA: PropTypes.string, }; export default ChildB;
跨层组件通信
详见 https://blog.csdn.net/weixin_41192489/article/details/138700487