一、ref 转发解决什么问题
1、使用自定义组件时,实现外层组件对原始组件(TextInput)的操作
外层组件使用 ref 属性
子组件使用 forwardRef 包裹
2、函数式组件对外暴露实例方法(cusomFocus)
子组件
父组件如图一所示
二、memo 解决什么问题?
1 、 避免多余渲染
问题:每次点击按钮都会导致 InfoView 组件发生重绘,即使每次 setInfo 都是一样的内容也是如此,这就是多余的
优化:给函数式组件 InfoView 外面包裹上 React.memo() ,比较前后 props 的值来决定是否发生重绘。
2、避免重复计算、重复创建对象
1、useMemo 缓存数据
在没有使用useMemo 时,仅改变组件中 showType 的状态,会导致组件重绘重新计算合计,而状态的变更并不会导致合计的计算结果发生变化,此时的计算就是多余的,就可以使用 useMemo 缓存函数计算结果,仅依赖条件 data 发生变化时才重新计算。useMemo 返回值是一个值而不是一个方法。
2、useMemo 缓存 UI 渲染
在合计这个 UI 模块,当数据源 data 不会发生改变的情况下,整个 UI 结构也是固定的,就可以直接缓存整个组件。
3、useCallback 缓存回调函数
问题:
- 在 1 处如果 view 组件重新渲染一次,每次都是会生成一个新的 onItemPress 函数对象。
- 在 2 处列表每生成一个 Item 组件就都会创建一个新的函数对象。
- 这些都是多余,没必要,无意义的操作。
优化:使用 useCallback 解决两层重复创建函数对象的问题
ps:
因为 onPress 只能接受无参的函数,无法直接调用,所以可以将函数改造成一个高阶函数,这样就返回了一个无参的函数。
const onItemPress = useCallback((item: any, index: any) => {
return () => {
console.log(`${item + index}`);
}
}, [])
三、高阶组件&高阶函数
高阶组件解决什么问题?
使用 HOC高阶组件解决横切关注点问题,使得组件功能更加单一,组件逻辑服务组件UI,从而降低耦合性,增强组件的复用性。
横切点关注点问题:
对于一个现有的组件而言,希望能在这个组件的某一个横切点去做一些事情,比如多渲染一个额外的视图,或者在组件的生命周期的某个节点去做一些事情,但是这个事情本身是和原始组件没有关系的。
什么是高阶函数?
如果一个函数接受的参数为函数,或者返回值是一个新函数,则该函数就是高阶函数。
setTimeout(() => {},1000);
array.filter((item, index) => item === target);
Promise...
什么是高阶组件?
如果一个组件的参数是组件,返回值是一个新组件,则该组件就是高阶组件。
高阶组件应用场景一(解耦):
如图所示,此处实现了一个添加按钮在页面右下角
1、如果不使用高阶组件能不能达到同样的效果?
答案是能,只需要在详情页面加一个按钮也能达到同样的效果
缺点:
- 所有的样式效果,功能模块都集中在一个页面里面了,即使有很多功能是与此页面的职责毫不相关,比如:页面中的添加按钮只是一个入口,与详情页是不相关的,它可以是在任何页面中显示,只是现在我们把它放到了详情页。这就是一种耦合,在详情页中添加这样一些与职责不相干的代码就是不合适的。
- 假设有很多个页面都需要这样的添加按钮,就需要写很多重复代码在不同的页面。
2、使用高阶组件就能有效解决这些问题。
将特定的样式,逻辑,全都写在高阶组件中,使用时只需要包裹一下需要使用高阶组件实现的特定的功能的组件,就能将高阶组件特定的功能赋予被包裹的组件。
而且通过简单的包裹就能有效的提高代码复用率。
// 高阶组件函数,接受一个泛型参数 T,表示组件类型,以及一个字符串参数 type
export default <T extends IReactComponent>(
OriginView: T | React.FC, // OriginView 参数可以是实现了 IReactComponent 接口的组件或函数式组件
type: string, // type 参数是一个字符串
): T => {
// 定义高阶组件内部的函数组件 HOCView
const HOCView = (props: any) => {
useEffect(() => {
// 空的 useEffect 钩子,可用于添加其他副作用逻辑
}, []);
return (
<>
{/* 渲染传入的原始组件,通过 {...props} 将所有 props 传递给原始组件 */}
<OriginView {...props} />
{/* 添加一个 TouchableOpacity 组件,当点击时执行 console.log 输出信息 */}
<TouchableOpacity
style={styles.addButton}
onPress={() => {
console.log('onPress ...', type);
}}>
<Image style={styles.addImg} source={icon_add} />
</TouchableOpacity>
</>
);
};
// 将 HOCView 转换为指定的泛型类型 T,并返回
return HOCView as T;
};
高阶组件使用场景二:
假设有一个需求:实现首页设备信息上报。(类似还有页面弹窗、申请系统权限等)
很简单的实现是:直接在首页页面的生命周期中发送请求,提交设备信息。
这里需要思考的是,上报设备信息这件事与首页的职能有关系吗?其实是没有关系的,只是这件事情刚好在首页发生了,在其他任何的页面上报设备信息都行,就这件事而言无论发生在哪里都是没有任何区别的。
从这个角度出发,把上报的代码直接写在首页就是不太合适的,这就出现了代码耦合,需要其解耦出去。
此处解耦的方式可以使用 hook 实现,也可以使用高阶组件实现。
高阶组件本质也是组件所以也有它自己的生命周期。
注意事项
1、不要改变传入的原始组件的原型
需要做的是在原始组件的基础上额外附加一些东西,不要对原始组件做任何改动
2、必要的话也是可以传入多个参数
四、Context 上下文
Context解决什么问题?
在一个典型的反应应用中,数据是通过 props 属性逐层传递,这种做法对于某些数据而言是极其繁琐的 (如:登陆信息,用户界面主题) ,这些数据应用中许多组件都需要,而Context 上下文提供了一种在组件间共享值的方式,而不必显式地通过组件树逐层传递。
这样就可以对一些全局数据进行直接共享
使用流程:
1、创建了一个名为ThemeContext的Context对象,用于在React应用程序中共享主题(theme)相关的数据,数据类型为字符串,并且默认值为’dark’。
import {createContext} from 'react';
export const ThemeContext = createContext<string>('dark');
2、使用<ThemeContext.Provider>
包裹根节点,这样组件树中的任何组件都可以通过Context访问backgroundStyle这个值。
Provider
这个命名惯例通常是为了表示在React中充当数据提供者的组件。
这是一种常见的命名模式,在React中,Context API中的数据提供者通常被称为 <SomeContext.Provider>
,其中 SomeContext
是你创建的Context对象的名称。
这个命名约定有几个好处:
-
明确的角色:使用
Provider
作为后缀,清晰地表明了组件的作用是提供数据给内部和子组件,有助于理解组件的用途。 -
语义化:可以根据组件的名称推断出它的作用,语义化的命名有助于代码的可维护性和可读性。
-
一致性:这种命名约定是React社区的共识,有助于减少混淆和提高协作的效率。
总之,Provider
命名约定是React中的一种通用惯例,用于标识充当数据提供者的组件,有助于更清晰地组织和理解React应用程序的组件结构。
3、在应用的任何一个页面,都能使用 useContext 取到值文章来源:https://www.toymoban.com/news/detail-810738.html
import React, {useContext} from 'react';
import {ThemeContext} from 'src/component/ThemeContext';
const HomeScreen: React.FC = () => {
const theme = useContext(ThemeContext);
return (<View></View>)
}
注意事项文章来源地址https://www.toymoban.com/news/detail-810738.html
- 因为Context本质上就是全局变量,大量使用Context会导致组件失去独立性,使组件复用性变差。
- 对于常规的组件间传值先考虑组件组合、状态管理、单例导出等方式,不要过度使用Context。
到了这里,关于React Native Ref转发/Memo缓存/HOC高阶组件/Context上下文的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!