react 组件应用

embedded/2024/11/14 12:28:56/

文章目录

    • react 组件
    • react 中组件 hook 函数应用
    • useMemo
    • 技术细节(useMemo 钩子函数和 useCallback 钩子函数)
    • 小结(依赖性数组应用)

react 组件

  1. 函数式组件实例及应用场景

    • 实例
      • 以下是一个简单的函数式组件,用于显示一个欢迎消息。
      import React from 'react';
      const WelcomeMessage = (props) => {return <h1>Welcome, {props.name}!</h1>;
      };
      export default WelcomeMessage;
      
      • 这个组件接收一个名为name的属性(props),并在h1标签中显示欢迎消息。它可以在其他组件中被这样使用:
      import React from 'react';
      import WelcomeMessage from './WelcomeMessage';
      const App = () => {return (<div><WelcomeMessage name="John" /></div>);
      };
      export default App;
      
    • 应用场景
      • 展示型组件:函数式组件非常适合用于展示型组件,这些组件主要用于将数据以某种形式展示给用户,没有复杂的内部状态或生命周期方法。例如,一个简单的文章列表组件,它接收文章数据作为属性,然后将每篇文章的标题、作者等信息展示出来。
      • 无状态逻辑组件:当组件不需要维护自己的状态,只是简单地根据传入的属性进行渲染时,函数式组件是很好的选择。像上面的欢迎消息组件,它只是根据传入的名字属性来显示消息,没有自己的内部状态。
      • 作为纯函数:函数式组件就像纯函数一样,对于相同的输入(属性),总是返回相同的输出(渲染结果)。这使得它们在性能优化方面具有优势,因为React可以更容易地判断组件是否需要重新渲染。例如,在一个数据可视化组件中,只要传入的数据(属性)没有变化,组件就不需要重新渲染。
  2. 类组件实例及应用场景

    • 实例
      • 下面是一个简单的类组件,用于实现一个计数器。
      import React, { Component } from 'react';
      class Counter extends Component {constructor(props) {super(props);this.state = {count: 0};}increment() {this.setState((prevState) => ({count: prevState.count + 1}));}render() {return (<div><p>Count: {this.state.count}</p><button onClick={() => this.increment()}>Increment</button></div>);}
      }
      export default Counter;
      
      • 这个类组件有一个内部状态count,初始值为0。有一个increment方法用于增加计数,在render方法中,它展示当前的计数,并提供一个按钮,点击按钮会调用increment方法来更新状态,从而重新渲染组件显示新的计数。
    • 应用场景
      • 有状态组件:类组件适合需要维护内部状态的场景。例如,在一个表单组件中,需要跟踪用户输入的各个字段的值,这些值就是组件的内部状态。像一个登录表单,需要记录用户输入的用户名和密码,并且可能还需要验证输入是否符合要求,这时候类组件的状态管理就很有用。
      • 复杂的生命周期管理:当组件需要在挂载、更新或卸载等不同生命周期阶段执行特定操作时,类组件是更好的选择。例如,在组件挂载时获取数据,在组件更新时根据新的数据重新计算某些值,在组件卸载时清理资源(如取消网络请求、清除定时器等)。比如,一个地图组件,在挂载时需要初始化地图,在更新时可能需要更新地图上的标记位置,在卸载时需要释放地图相关的资源,使用类组件可以更好地利用生命周期方法来实现这些功能。
      • 与第三方库集成:如果需要在组件中集成第三方库,并且这些库需要与组件的生命周期进行交互,类组件会更方便。例如,在使用一些动画库时,可能需要在组件挂载时启动动画,在组件卸载时停止动画,通过类组件的生命周期方法可以很好地控制这些操作。

react 中组件 hook 函数应用

  1. React组件传值

    • 父组件向子组件传值(Props)
      • 实例
        • 首先创建一个父组件ParentComponent和一个子组件ChildComponent
        import React from 'react';
        import ChildComponent from './ChildComponent';
        const ParentComponent = () => {const message = "Hello from Parent";return (<div><ChildComponent passedMessage={message} /></div>);
        };
        export default ParentComponent;
        
        • 子组件接收passedMessage属性并显示它。
        import React from 'react';
        const ChildComponent = (props) => {return (<div><p>{props.passedMessage}</p></div>);
        };
        export default ChildComponent;
        
      • 解释:在父组件中,定义了一个变量message,然后将这个变量作为属性passedMessage传递给子组件ChildComponent。在子组件中,通过props.passedMessage来访问这个传递过来的值,并将其渲染在p标签中。
    • 子组件向父组件传值(回调函数)
      • 实例
        • 父组件定义一个函数来接收子组件传递的值。
        import React from 'react';
        import ChildComponentWithCallback from './ChildComponentWithCallback';
        const ParentComponentWithCallback = () => {const handleChildValue = (valueFromChild) => {console.log("Received value from child: ", valueFromChild);};return (<div><ChildComponentWithCallback sendValueToParent={handleChildValue} /></div>);
        };
        export default ParentComponentWithCallback;
        
        • 子组件调用父组件传递过来的函数来传递值。
        import React from 'react';
        const ChildComponentWithCallback = (props) => {const valueToSend = "Value from Child";const sendValue = () => {props.sendValueToParent(valueToSend);};return (<div><button onClick={sendValue}>Send Value to Parent</button></div>);
        };
        export default ChildComponentWithCallback;
        
      • 解释:在父组件中,handleChildValue函数用于接收子组件传递的值。这个函数作为属性sendValueToParent传递给子组件。在子组件中,当按钮被点击时,sendValue函数被调用,它会调用props.sendValueToParent并将valueToSend作为参数传递,这样就实现了子组件向父组件传值。
  2. Hook函数应用实例

    • useState Hook
      • 实例
        • 用于在函数式组件中添加状态。
        import React, { useState } from 'react';
        const CounterHook = () => {const [count, setCount] = useState(0);const increment = () => {setCount(count + 1);};return (<div><p>Count: {count}</p><button onClick={increment}>Increment</button></div>);
        };
        export default CounterHook;
        
      • 解释useState是一个Hook函数,它返回一个数组,数组的第一个元素是状态变量(count),第二个元素是用于更新这个状态变量的函数(setCount)。初始状态值为0。当按钮被点击时,increment函数被调用,它使用setCount来更新count的值,从而导致组件重新渲染并显示新的计数。
    • useEffect Hook
      • 实例
        • 用于在组件挂载、更新或卸载时执行副作用操作,如获取数据、订阅事件等。
        import React, { useState, useEffect } from 'react';
        const DataFetchingComponent = () => {const [data, setData] = useState([]);useEffect(() => {const fetchData = async () => {const response = await fetch('https://example.com/api/data');const jsonData = await response.json();setData(jsonData);};fetchData();}, []);return (<div>{data.map((item) => (<p key={item.id}>{item.name}</p>))}</div>);
        };
        export default DataFetchingComponent;
        
      • 解释useEffect接受一个函数作为参数。在这个例子中,函数内部定义了一个异步函数fetchData来从API获取数据。获取到数据后,使用setData来更新状态。第二个参数[]表示这个useEffect只在组件挂载时执行一次。如果省略这个参数,useEffect会在组件每次更新时都执行。如果想在某些特定状态变化时执行useEffect,可以将这些状态变量放在数组中,例如[count],这样当count状态改变时,useEffect就会执行。
    • useContext Hook
      • 实例
        • 用于在组件树中共享数据,避免了层层传递属性的麻烦。
        • 首先创建一个上下文(Context)。
        import React from 'react';
        const MyContext = React.createContext();
        
        • 然后在一个父组件中提供这个上下文的值。
        import React from 'react';
        import MyContext from './MyContext';
        import ChildComponentUsingContext from './ChildComponentUsingContext';
        const ParentComponentWithContext = () => {const sharedValue = "This is a shared value";return (<MyContext.Provider value={sharedValue}><ChildComponentUsingContext /></MyContext.Provider>);
        };
        export default ParentComponentWithContext;
        
        • 最后在子组件中使用useContext来获取这个共享的值。
        import React, { useContext } from 'react';
        import MyContext from './MyContext';
        const ChildComponentUsingContext = () => {const sharedValue = useContext(MyContext);return (<div><p>{sharedValue}</p></div>);
        };
        export default ChildComponentUsingContext;
        
      • 解释React.createContext创建了一个上下文对象。在ParentComponentWithContext中,通过MyContext.Provider来提供一个共享的值sharedValue。在ChildComponentUsingContext中,useContext(MyContext)用于获取这个共享的值,并将其渲染在p标签中。这样,无论组件层次有多深,只要在MyContext.Provider的范围内,都可以方便地获取这个共享值。

useMemo

  1. 基本概念

    • useMemo是一个React Hook,它用于缓存计算结果。其主要目的是通过记忆(memorization)来避免在每次组件重新渲染时都进行昂贵的计算。这样可以优化性能,特别是当计算过程复杂或者依赖的数据频繁变化时。
  2. 语法和参数

    • 语法:const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
    • 第一个参数是一个函数,这个函数包含了需要进行记忆化的计算。例如,这个函数可能是对一个大型数组进行过滤、排序或者其他复杂的操作。
    • 第二个参数是一个依赖项数组。这个数组中的元素是当它们发生变化时,useMemo才会重新运行第一个参数中的计算函数,以更新memoizedValue。如果依赖项数组为空,那么计算函数只会在组件初次渲染时执行一次。
  3. 应用实例

    • 避免重复计算
      • 假设我们有一个组件,用于计算并显示一个非常大的斐波那契数列。斐波那契数列的计算是比较复杂的,而且如果没有优化,每次组件渲染都会重新计算整个数列。
      import React, { useState, useMemo } from 'react';
      const FibonacciCalculator = () => {const [n, setN] = useState(10);// 使用useMemo来缓存斐波那契数列的计算结果const fibonacciSequence = useMemo(() => {const sequence = [0, 1];for (let i = 2; i <= n; i++) {sequence.push(sequence[i - 1] + sequence[i - 2]);}return sequence;}, [n]);return (<div><inputtype="number"value={n}onChange={(e) => setN(Number(e.target.value))}/><p>斐波那契数列前{n}项: {fibonacciSequence.join(', ')}</p></div>);
      };
      export default FibonacciCalculator;
      
      • 解释:在这个组件中,useMemo用于缓存斐波那契数列的计算结果。当n的值发生变化时(通过输入框改变n的值),useMemo会重新运行计算斐波那契数列的函数,因为nuseMemo的依赖项。如果n没有变化,即使组件因为其他原因(比如父组件重新渲染)重新渲染,fibonacciSequence的值也不会重新计算,而是直接使用之前缓存的值。
    • 优化子组件渲染
      • 考虑一个场景,父组件有一个状态值,这个状态值会导致父组件频繁重新渲染,但是子组件只有在特定数据变化时才需要重新渲染。
      import React, { useState, useMemo } from 'react';
      const ParentComponent = () => {const [count, setCount] = useState(0);const [data, setData] = useState([1, 2, 3]);// 假设这是一个复杂的计算,用于过滤数据const filteredData = useMemo(() => {return data.filter((item) => item > 1);}, [data]);return (<div><button onClick={() => setCount(count + 1)}>Increment Count (This causes Parent to re - render)</button><ChildComponent data={filteredData} /></div>);
      };
      const ChildComponent = ({ data }) => {return (<div>{data.map((item) => (<p key={item}>{item}</p>))}</div>);
      };
      export default ParentComponent;
      
      • 解释:在ParentComponent中,count状态的变化会导致父组件重新渲染。但是,通过useMemo缓存了filteredData的计算结果,只要data没有变化,filteredData就不会重新计算,传递给ChildComponent的数据也不会改变。这样,即使父组件因为count的变化重新渲染,ChildComponent也不会重新渲染,除非data发生变化,从而优化了子组件的渲染性能。

技术细节(useMemo 钩子函数和 useCallback 钩子函数)

  1. 基本概念和用途

    • useMemo
      • 主要用于缓存计算结果。它会记住一个函数的返回值,只有当依赖项发生变化时,才会重新计算这个返回值。这个返回值可以是任何类型的数据,比如一个复杂的计算结果、一个经过处理的数据数组等。
      • 目的是避免在每次组件渲染时都进行昂贵的计算,以提高性能。
    • useCallback
      • 用于缓存函数本身。它返回一个记忆化(memoized)的函数,只有当依赖项发生变化时,这个记忆化的函数才会重新创建。
      • 通常用于在组件中传递回调函数,以避免在不必要的情况下重新创建函数,从而防止子组件因为接收到新的函数引用而重新渲染。
  2. 语法对比

    • useMemo
      • 语法:const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
      • 第一个参数是一个返回需要缓存的值的函数,第二个参数是一个依赖项数组,用于确定何时重新计算这个值。
    • useCallback
      • 语法:const memoizedCallback = useCallback(() => doSomething(a, b), [a, b]);
      • 第一个参数是需要缓存的函数本身,第二个参数同样是依赖项数组,用于决定何时重新创建这个函数。
  3. 应用场景对比

    • useMemo
      • 复杂计算的缓存
        • 例如,在一个数据可视化组件中,需要对大量的数据进行复杂的统计计算,如计算平均值、标准差等。
        import React, { useState, useMemo } from 'react';
        const DataVisualizationComponent = () => {const [data, setData] = useState([1, 2, 3, 4, 5]);// 计算平均值并缓存结果const average = useMemo(() => {const sum = data.reduce((acc, val) => acc + val, 0);return sum / data.length;}, [data]);return (<div><p>数据平均值: {average}</p></div>);
        };
        export default DataVisualizationComponent;
        
        • 解释:每次data发生变化时,useMemo会重新计算平均值;如果data不变,即使组件因为其他原因重新渲染,也会直接使用缓存的平均值,避免了重复计算。
      • 避免数据处理的重复执行
        • 假设要对一个文本字符串进行复杂的格式化操作,如将一段包含HTML标签的文本转换为纯文本并进行单词计数。
        import React, { useState, useMemo } from 'react';
        const TextProcessingComponent = () => {const [text, setText] = useState("<p>Hello, World!</p>");// 缓存格式化后的文本和单词计数结果const [formattedText, wordCount] = useMemo(() => {const plainText = text.replace(/<[^>]*>/g, "");const words = plainText.split(" ").length;return [plainText, words];}, [text]);return (<div><p>格式化后的文本: {formattedText}</p><p>单词计数: {wordCount}</p></div>);
        };
        export default TextProcessingComponent;
        
        • 解释:useMemo确保只有当text发生变化时,才会重新进行文本格式化和单词计数操作。
    • useCallback
      • 优化子组件渲染(传递回调函数)
        • 考虑一个包含列表和删除按钮的组件,点击删除按钮会调用一个回调函数来删除列表中的某个元素。
        import React, { useState, useCallback } from 'react';
        const ParentListComponent = () => {const [list, setList] = useState([1, 2, 3]);// 记忆化删除函数const handleDelete = useCallback((index) => {const newList = [...list];newList.splice(index, 1);setList(newList);}, [list]);return (<div>{list.map((item, index) => (<ChildListItem key={item} item={item} onDelete={handleDelete(index)} />))}</div>);
        };
        const ChildListItem = ({ item, onDelete }) => {return (<div><p>{item}</p><button onClick={onDelete}>删除</button></div>);
        };
        export default ParentListComponent;
        
        • 解释:useCallback用于缓存handleDelete函数。只有当list发生变化时,handleDelete函数才会重新创建。这样,在ParentListComponent重新渲染时,如果list没有变化,传递给ChildListItemonDelete函数引用不会改变,从而避免了ChildListItem因为函数引用改变而不必要地重新渲染。
      • 事件处理函数的优化
        • 例如,在一个游戏组件中有多个按钮,每个按钮都有自己的点击事件处理函数,这些函数可能会根据游戏状态(如得分、关卡等)进行一些操作。
        import React, { useState, useCallback } from 'react';
        const GameComponent = () => {const [score, setScore] = useState(0);const [level, setLevel] = useState(1);// 记忆化加分事件处理函数const handleAddScore = useCallback(() => {setScore(score + 10);}, [score]);// 记忆化升级事件处理函数const handleLevelUp = useCallback(() => {setLevel(level + 1);}, [level]);return (<div><button onClick={handleAddScore}>加分</button><button onClick={handleLevelUp}>升级</button></div>);
        };
        export default GameComponent;
        
        • 解释:useCallback确保每个事件处理函数只有在其依赖的游戏状态(scorelevel)发生变化时才会重新创建。这有助于在游戏状态更新时,只重新渲染与状态变化相关的部分,提高性能。

小结(依赖性数组应用)

  1. 理解依赖项数组的作用

    • useMemouseCallback和其他类似的React钩子(如useEffect)中,依赖项数组用于告诉React在哪些值发生变化时,需要重新执行相关的操作。例如,在useMemo中,当依赖项数组中的元素变化时,会重新计算缓存的值;在useCallback中,依赖项的变化会导致回调函数重新创建。
  2. 分析组件内部的逻辑和状态使用情况

    • 数据读取与计算
      • 识别使用的数据:仔细查看在计算或函数内部使用了哪些变量、状态(state)或属性(props)。例如,在一个useMemo钩子中,如果是计算一个购物车商品总价,并且总价是根据商品数量和单价来计算的,那么商品数量和单价就是依赖项。
      • 考虑数据来源:如果数据来自组件的状态(通过useState定义)、父组件传递的属性(props)或者其他外部数据源(如context),这些都有可能是依赖项。例如,在一个展示用户信息的组件中,用户的姓名、年龄等属性是从父组件传递过来的,那么这些props就应该在依赖项数组中,因为如果这些信息改变,组件的展示可能需要更新。
    • 函数调用与副作用操作
      • 检查函数内部调用的函数:如果在useCallback定义的函数内部调用了其他函数,并且这些函数的行为可能因为某些数据的变化而改变,那么这些数据对应的变量也可能是依赖项。例如,在一个表单提交的回调函数中,调用了一个验证表单数据的函数,而验证函数可能依赖于表单的某些字段,这些字段对应的变量就是依赖项。
      • 副作用操作相关的数据:对于useEffect钩子,考虑在其中执行的副作用操作(如数据获取、订阅事件等)依赖于哪些数据。如果在组件挂载时通过fetch获取数据,并且数据的URL是根据某个状态变量确定的,那么这个状态变量就是useEffect的依赖项。
  3. 遵循最小化依赖原则

    • 只包含真正会影响计算或操作的元素。例如,在一个简单的计数器组件中,有一个increment函数用于增加计数,一个doubleCount函数(通过useMemo缓存)用于计算计数的两倍。doubleCount函数只依赖于计数变量,而不依赖于increment函数,所以在useMemo的依赖项数组中只需要包含计数变量。
    • 避免包含不必要的元素,因为这可能导致过度重新计算或重新创建函数。如果不小心包含了一个不会影响操作的变量,那么每次这个变量变化时,都会触发不必要的重新计算或重新创建,降低性能。例如,在一个组件中,有一个用于显示当前日期的函数(通过useMemo缓存),这个函数只依赖于日期相关的状态,而不依赖于一个用于切换主题的变量,那么主题变量就不应该出现在useMemo的依赖项数组中。
  4. 动态依赖项的情况

    • 有时候依赖项可能是动态生成的,例如,一个根据用户权限动态加载不同模块的组件。在这种情况下,可以考虑使用一个更高级的技术,如使用useReducer来管理状态,或者在useEffect中动态地添加和移除事件监听器,并且根据具体情况更新依赖项数组。但是这种情况比较复杂,需要谨慎处理,因为不当的操作可能导致内存泄漏或其他性能问题。
    • 如果依赖项是一个对象或数组,并且对象或数组的内容可能会改变而引用不变(例如,修改对象的属性而不是重新创建对象),React可能无法正确检测到变化。在这种情况下,可以考虑使用一些辅助函数,如React.useMemo来创建一个新的引用,或者使用Object.assign[...array]等方式来创建新的对象或数组,并且将这些新的引用作为依赖项。

http://www.ppmy.cn/embedded/137199.html

相关文章

深度学习经典模型之VGGNet

1 VGGNet 1.1 模型介绍 ​ VGGNet是由牛津大学视觉几何小组&#xff08;Visual Geometry Group, VGG&#xff09;提出的一种深层卷积网络结构&#xff0c;他们以7.32%的错误率赢得了2014年ILSVRC分类任务的亚军&#xff08;冠军由GoogLeNet以6.65%的错误率夺得&#xff09;和…

开源 - Ideal库 - 常用枚举扩展方法(一)

今天和大家享一些关于枚举操作相关的常用扩展方法。 我们平时用的比较多的是正常枚举&#xff0c;同时还有加[Flags]特性的位标志枚举&#xff0c;因此以下所有扩展方法同时适用正常枚举以及位标志枚举。 我们首先定义两种枚举用于下面扩展方法测试适用&#xff0c;代码如下&a…

Linux内核编程(二十)RTC子系统一驱动rx8010

本文目录 一、基础知识点1.什么是RTC&#xff1f;2. RTC方案3. 电路原理图 二、RTC芯片&#xff08;RX8010&#xff09;移植三、关于时间的一些命令四、应用层使用1. 使用RTC驱动2. 使用time.h库&#xff08;额外知识点&#xff09; 一、基础知识点 1.什么是RTC&#xff1f; R…

Excel 无法打开文件

Excel 无法打开文件 ‘新建 Microsoft Excel 工作表.xlsx",因为 文件格式或文件扩展名无效。请确定文件未损坏&#xff0c;并且文件扩展名与文件的格式匹配。 原因是卸载WPS之后&#xff0c;注册表未修改过来。 重新下载WPS&#xff0c;新建&#xff0c;xls工作表&#x…

Vue3 -- 新组件【谁学谁真香系列6】

Teleport Teleport是什么?–Teleport是一种能够将我们的组件html结构移动到指定位置的技术。 父组件: <template><div calss="outer"><h2>我是App组件</h2><img src="https://z1.ax1x.com/2023/11/19/piNxLo4.jpg" alt=&qu…

Prompt Engineering Guide

文章目录 Prompt Engineering Guide提示工程简介基本概念包含要素要避免不明确的prompt技术关注做了什么&#xff0c;不要关注不做什么角色提示Role Prompting 提示技术CoT生成的知识作为预测的知识库判断的一部分Prompting ChainingToT思维链检索增强RAGPrompt策略分析 提示应…

STM32WB55RG开发(3)----生成 BLE 程序连接手机APP

STM32WB55RG开发----3.生成 BLE 程序连接手机APP 概述硬件准备视频教学样品申请源码下载参考程序选择芯片型号配置时钟源配置时钟树RTC时钟配置RF wakeup时钟配置查看开启STM32_WPAN条件配置HSEM配置IPCC配置RTC启动RF开启蓝牙设置工程信息工程文件设置结果演示 概述 本项目旨…

探索深度学习的本质

深度学习的本质是利用多层&#xff08;深层&#xff09;的神经网络结构来从数据中学习复杂的模式和特征。其主要特点是具有层次结构&#xff0c;能够实现自动特征提取。非线性、可扩展性和迁移学习能力是深度学习能够处理复杂问题和广泛&#xff08;低成本&#xff09;应用的关…