什么是组件一个组件就是用户界面的一部分它可以有自己的逻辑和外观。组件之间可以互相嵌套也可以复用多次为什么要用组件组件能让开发者像搭积木一样快速构建一个完整的庞大应用大大提升了开发效率降低了维护成本因此当下前端的主流开发模式即组件化开发定义组件react 中的组件有以下特征是一个首字母大写的函数函数的返回值是一段 JSX 代码用于渲染页面通常每个组件都用独立的.jsx文件描述并用export default对外导出return 返回的语句写在一行则可以省略() 但只要不在一行就必须要 () 所以建议总是加上 ()returnimg srchttps://i.imgur.com/MK3eW3As.jpgaltKatherine Johnson/;范例 Demo.jsxfunctionDemo(){returndiv你好/div;}exportdefaultDemo;也可以写成箭头函数constDemo(){returndiv你好/div;};exportdefaultDemo;高阶组件 HOC注意现代更主流的做法是使用 HOOK 来实现代码复用而不是使用 HOC但仍需会 HOC 因为老项目中是 HOC若一个组件的参数是组件返回值是一个新组件则它就是一个高阶组件。高阶组件HOC, Higher-Order Component的核心作用是复用逻辑和增强组件功能。通常约定以小写字母开头【实战范例】汉堡套餐HOC// 汉堡套餐生成器constwithCombo(Food){return(props)(div{/* 汉堡本尊 */}Food{...props}/{/* 自动附赠的薯条和可乐 */}Fries/Coke//div)}使用// 传入双层芝士汉堡得到双层芝士汉堡套餐含薯条和可乐constDoubleCheeseBurgerWithCombowithCombo(DoubleCheeseBurger)【实战范例】权限控制HOCfunctionwithAuth(WrappedComponent,requiredRoleuser){returnfunctionAuthWrapper(props){const{user}useAuth();// 假设使用自定义Hook获取用户// 检查是否已登录if(!user){returnRedirect to/login/;}// 检查是否有权限if(requiredRoleadminuser.role!admin){returnUnauthorized message需要管理员权限/;}// 有权限则正常渲染returnWrappedComponent{...props}user{user}/;};}// 使用constAdminPanelwithAuth(AdminPanelBase,admin);constUserProfilewithAuth(UserProfileBase,user);使用组件以在 App.jsx 中使用为例先导入importDemofrom./Demo.js;再使用functionApp(){return(Demo//);}可以单标签自闭也可以像 html 一样双标签配对Demo/Demo组件通信即组件间相互传递数据父组件传值给子组件Avatar person{{name:Lin Lanying,imageId:1bX5QH6}}size{100}/或letme{name:朝阳,age:18,};Persion{...me}/此种写法要留意顺序Persion{...me}age{36}/此时 age 最终值为 36后方的属性会覆盖前方的属性父组件给子组件传递 JSX 内容插槽 children使用子组件时其标签内的内容即插槽在子组件中可通过 children 获取到父组件importChildfrom./child.jsx;functionFather(){return(Child你好/Child/);}exportdefaultFather;子组件functionChild({children}){return(h1我是子组件/h1div父组件传入的插槽内容为{children}/div/);}exportdefaultChild;具名插槽https://blog.csdn.net/weixin_41192489/article/details/139835331动态插槽https://blog.csdn.net/weixin_41192489/article/details/157583866父组件调用子组件的方法useImperativeHandle 暴露子组件的方法forwardRef 暴露子组件React19 中 forwardRef 不再必须可以直接把 ref 当普通 props 传递不使用 forwardRef// React19新写法不再需要forwardRef包裹Child ref{childRef}/functionChild({ref}){constinneruseRef(null)useImperativeHandle(ref,()({...}))returninput ref{inner}/}使用 forwardRefimport React,{useRef,useImperativeHandle,forwardRef}fromreact;// 子组件函数组件constChildComponentforwardRef((props,ref){constinnerRefuseRef(null);// 定义暴露给父组件的方法useImperativeHandle(ref,()({focus:(){innerRef.current.focus();},showMessage:(){console.log(这是子组件的方法);}}));returninput ref{innerRef}typetext/;});// 父组件functionParentComponent(){constchildRefuseRef(null);consthandleClick(){// 调用子组件的方法childRef.current.showMessage();childRef.current.focus();};return(divbutton onClick{handleClick}调用子组件方法/buttonChildComponent ref{childRef}//div);}父组件获取子组件的DomforwardRef 暴露子组件父组件中通过 ref 属性将定义的 inputRef 传给子组件子组件通过第二个参数 prop_ref 获取到父组件传入的 inputRef子组件的目标元素通过 ref 属性绑定 prop_ref父组件constinputRefuseRefTextInput(null);useEffect((){inputRef.current?.focus();// 通过 ref 调用 focus 方法},[]);Test ref{inputRef}/子组件import{forwardRef}fromreact;import{TextInput,View}fromreact-native;// eslint-disable-next-line react/display-nameexportdefaultforwardRefTextInput((props,prop_ref){return(ViewTextInput ref{prop_ref}//View);});子组件获取父组件的传值 propsfunctionAvatar({person,size}){// 直接访问 person 和 size 即可}或functionAvatar(props){letpersonprops.person;letsizeprops.size;}指定 props 的默认值functionAvatar({person,size100}){}或Avatar.defaultProps{size:100,};给 props 添加类型校验 propTypesPropTypes是React提供的一个用于类型检查的库。它可以用来验证组件的属性props是否符合预期的类型和格式importPropTypesfromprop-types;写在组件函数外Avatar.propTypes{person:PropTypes.object,size:PropTypes.number,};添加必填校验 .isRequired在末尾添加 .isRequiredAvatar.propTypes{person:PropTypes.object.isRequired,size:PropTypes.number,};数据类型检查器PropTypes.stringPropTypes.symbolPropTypes.numberPropTypes.bigintPropTypes.boolPropTypes.funcPropTypes.arrayPropTypes.object节点类型检查器PropTypes.nodePropTypes.elementPropTypes.elementType子组件传值给父组件实现方案在子组件中调用父组件传给子组件的函数参数为要传递的值注意使用可选链运算符?.来确保安全避免因传入的方法不存在而报错。functionPersion({name,age,handleAgeChange}){return(h1你好{name}/h1p你今年{age}岁。/p{/* 可选链运算符 ?.允许在访问对象的属性或调用对象的方法时不必先检查该对象是否存在 */}button onClick{()handleAgeChange?.(36)}更新年龄为36/button/);}functionApp(){// 使用 useState 钩子管理状态确保状态更新时组件会重新渲染const[me,setMe]useState({name:朝阳,age:18,});consthandleAgeChange(newAge){// 使用 setMe 函数更新状态而不是直接修改对象setMe(prevState({...prevState,age:newAge}));};return(Persion{...me}handleAgeChange{(newAge){/* 触发父组件状态更新 */handleAgeChange(newAge);}}//);}子组件调用父组件的方法实现方案在子组件中调用父组件传给子组件的函数父组件import{useState}fromreact;importChildfrom./child.jsx;functionFather(){const[name,setName]useState(朝阳);functionchangeName(){setName(新的朝阳);}return(h1我是父组件/h1p父组件中的变量 name 的值为{name}/pChild changeName{changeName}/Child/);}exportdefaultFather;子组件importPropTypesfromprop-types;functionChild({changeName}){return(h1我是子组件/h1button onClick{changeName}修改父组件的名字为“新的朝阳”/button/);}Child.propTypes{changeName:PropTypes.func,};exportdefaultChild;兄弟组件通信father.jsximport{useState}fromreact;importChildAfrom./childA.jsx;importChildBfrom./childB.jsx;functionFather(){const[msgA,setMsgA]useState();functionsendMsgToB(msg){setMsgA(msg);}return(ChildA sendMsgToB{sendMsgToB}/ChildB msgA{msgA}//);}exportdefaultFather;childA.jsximportPropTypesfromprop-types;functionChildA({sendMsgToB}){constdataA子组件A的数据;return(divh1我是子组件A/h1button onClick{()sendMsgToB(dataA)}向子组件B传递数据/button/div/);}ChildA.propTypes{sendMsgToB:PropTypes.func,};exportdefaultChildA;childB.jsximportPropTypesfromprop-types;functionChildB({msgA}){return(divh1我是子组件B/h1p子组件A传来的数据为{msgA}/p/div/);}ChildB.propTypes{msgA:PropTypes.string,};exportdefaultChildB;跨层组件通信详见 https://blog.csdn.net/weixin_41192489/article/details/138700487