React Native Ref转发/Memo缓存/HOC高阶组件/Context上下文

news/2024/7/15 18:33:47 标签: react native, react.js

一、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对象的名称。

这个命名约定有几个好处:

  1. 明确的角色:使用 Provider 作为后缀,清晰地表明了组件的作用是提供数据给内部和子组件,有助于理解组件的用途。

  2. 语义化:可以根据组件的名称推断出它的作用,语义化的命名有助于代码的可维护性和可读性。

  3. 一致性:这种命名约定是React社区的共识,有助于减少混淆和提高协作的效率。

总之,Provider 命名约定是React中的一种通用惯例,用于标识充当数据提供者的组件,有助于更清晰地组织和理解React应用程序的组件结构。

3、在应用的任何一个页面,都能使用 useContext 取到值

import React, {useContext} from 'react';
import {ThemeContext} from 'src/component/ThemeContext';
const HomeScreen: React.FC = () => {
  const theme = useContext(ThemeContext);
  return (<View></View>)
}

注意事项

  • 因为Context本质上就是全局变量,大量使用Context会导致组件失去独立性,使组件复用性变差。
  • 对于常规的组件间传值先考虑组件组合、状态管理、单例导出等方式,不要过度使用Context。

http://www.niftyadmin.cn/n/5342976.html

相关文章

手势识别MATLAB代码

手势识别是智能设备常用的需求, 下面我们用MATLAB来识别手部的形态: 主程序main.m clc;clear all;close all;%清除命令行和窗口 imimread(DSC05815.JPG); [skin,bwycbcr,w,h] hand_segmentation(im); im1bwycbcr; % se strel(ball,[1 1 1;1 1 1;1 1 1]); im1 imdilate(im…

Git将当前分支暂存切换到其他分支

在我们使用Git进行版本控制时&#xff0c;经常会遇到这样的情况&#xff1a;我们正在一个分支上进行一些修改&#xff0c;但突然需要切换到另一个分支进行一些操作。这时&#xff0c;我们可以使用git stash命令来暂存我们的修改&#xff0c;然后再切换到其他分支。下面&#xf…

基础支撑平台(企业集成平台)建设方案-word

基础支撑平台主要承担系统总体架构与各个应用子系统的交互&#xff0c;第三方系统与总体架构的交互。需要满足内部业务在该平台的基础上&#xff0c;实现平台对于子系统的可扩展性。基于以上分析对基础支撑平台&#xff0c;提出了以下要求&#xff1a; 基于平台的基础架构&…

基于taro搭建小程序多项目框架

前言 为什么需要这样一个框架&#xff0c;以及这个框架带来的好处是什么&#xff1f; 从字面意思上理解&#xff1a;该框架可以用来同时管理多个小程序&#xff0c;并且可以抽离公用组件或业务逻辑供各个小程序使用。当你工作中面临这种同时维护多个小程序的业务场景时&#xf…

012vuerouter

VUEROUTER3–vue2 vuerouter4–vue3 一个html可以切换多个组件&#xff0c;用户体验好很多 使用&#xff1a;导入-全局注册&#xff08;use import vuerouter from vuerouter Vue.use(vuerouter) vue-router有 < router-link > 并且使用< router-view>来声明路由…

java获取一个视频的时长

引言 在日常开发中&#xff0c;经常会遇到产品经理提出一个需求“上传视频”&#xff0c;而且还得显示出视频的播放时长&#xff0c;我们直接上最简单的代码 How to do 1.​​​​​​​提前引入包 <!--视频多媒体工具包 包含 FFmpeg、OpenCV--><dependency>&l…

基于SpringBoot Vue航空机票预订系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

Oracle 19c RAC集群管理 ---------关键参数以及常用命令

Oracle 19c RAC集群管理 ---------关键参数 Oracle 19C RAC 参数最佳实践 --开启强制归档 ALTER DATABASE FORCE LOGGING; --设置 30分钟 强制归档 ALTER SYSTEM SET ARCHIVE_LAG_TARGET1800 SCOPEBOTH SID*; --设置期望undo保持时间3h ALTER SYSTEM SET UNDO_RETENTION21600…