赞
踩
大背景:
Facebook
的内部项目,因为对市面上所有JS MVC框架不满意,就自己开发了一套,用来开发Instagram项目。(开源时间:2013年5月)三句话解释:
主要特点:
下面,我们再来与Vue进行对比,更为深入地了解React的特点
虚拟Dom + Diff算法
的渲染机制,用于提升渲染速度组件化开发
,通过props传参等方式进行父子数据通信状态管理
(Vue的Vuex/Pinia,React的Redux/Mobx)跨平台开发
(Vue的Uniapp,React的React Native)框架层面:
MVVM
模式(由MVC发展出来的)双向数据流
MVC
中的View层单向数据流
数据层面:
双向绑定
。数据可变
,当数据发生变化,可通过 getter/setter 以及一些 函数的劫持
监听数据的变化不可变(Immutable)
,为 单向数据流
。数据不可变
,所以React无需监听数据的变化,React只对setState之后会有重新渲染的流程引用的方式(Diff)
进行的,所以若是不优化,则会导致大量非必要渲染,从而影响性能(代码要求更高)渲染层面:
shouldComponentUpdate
这个生命周期函数进行控制。Diff 算法:
边对比,边更新DOM
。统一操作批量更新DOM
。其他层面:
接下来,我们继续来了解React的核心内容:
我们在简介里,已经了解到,JSX全称为JavaScript XML,是JavaScript的一种语法扩展。本质是 React.createElement
的语法糖,即创建虚拟DOM的方法
。
解决痛点: 为了简化创建虚拟DOM
,无需每次嵌套使用 React.createElement。
简易写法:
const element = <h1>Hellow World!!!<h1/>
语法规范:
const MyComponent = () => { const divStyle = { color: 'blue', backgroundColor: 'yellow', padding: '10px', border: '1px solid black' }; return ( <> <div className="divClass">外链样式</div> <div style={divStyle}>内嵌样式</div> </> ); }; export default MyComponent;
JSX可嵌入变量和表达式(运算符、函数调用)
,绑定属性和方法
。
import React, { useState } from 'react'; const MyComponent = () => { // 嵌入变量 const name = 'React Developer'; const age = 25; // 使用useState来管理一个状态变量 const [visible, setVisible] = useState(true); // 嵌入表达式 - 函数调用(例如,计算年龄的平方) const ageSquared = () => age * age; const handleClick = () => { setVisible(!visible); } return ( <> {/* 嵌入变量 */} <p>Name: {name}</p> <p>Age: {age}</p> {/* 嵌入表达式 - 运算符 */} <p>Age Squared: {age * age}</p> {/* 嵌入表达式 - 三元 */} <p>Is Age Blow 20: {age < 20 ? 'Yes' : 'No'}</p> {/* 嵌入表达式 - 函数调用 */} <p>Age Squared: {ageSquared()}</p> {/* 绑定属性(事件处理器) */} <button onClick={handleClick}> {visible ? 'Hide' : 'Show'} </button> </> ); } export default MyComponent;
常见的条件渲染,有以下三种方式:
条件函数判断
:适合逻辑多,拆解成函数,进行if,switch 或策略模式三元运算符
:适合逻辑简单的,最好就单层。与运算符&&
:条件成立渲染后面的标签或组件。import React, { useState } from 'react'; import Admin from './Admin'; // 假设Admin组件在'./Admin'文件中 const MyComponent = () => { const [userRole, setUserRole] = useState(1); const changeUserRole = (role) => { setUserRole(role === 1 ? 2 : 1) } // 函数条件判断 const roleComponents = () => { if(userRole === 1) return <Admin /> else return null; } return ( <> <button onClick={changeUserRole}>切换身份</button> {/* 条件函数 */} {roleComponents()} {/* 三元运算 */} {role === 1 ? <Admin /> : null} {/* 与运算 */} {role === 1 && <Admin />} </> ) } export default MyComponent;
我们一般使用 map函数
来遍历数组,如下面的代码所示:
function MyComponent() { const lists = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']; return ( <> <h1>Fruit List</h1> <ul> {lists.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> </> ); } export default MyComponent;
注:key 和 React 中的 Diff 算法密切相关。所以我们需要给每个map列表循环加上key值。
不然会报错:warning: Each child in a list should have a unique “key” prop.
组件化是一种高效的处理复杂应用系统,更好的明确功能模块作用的方式。即为一种分而治之的思想。
而React整个框架都围绕着组件化这一核心概念展开,可以说组件化是React的核心思想。
React一开始,以类组件作为主体,在React16.8版本(引入React Hooks
)后,解决了类组件的部分痛点(Hooks部分再说明),函数组件后来者居上。
定义特点:
实现方式:
import React, { Component } from 'react'; export default class App extends Component { constructor() { super(); this.state = {}; } render() { return ( <div> <h1>我是类组件</h1> </div> ); } }
函数组件,字面意思,就是JavaSript函数作为React组件。
定义特点:
无生命周期函数
,可用useEffect替代无状态管理
,可用useState替代// 定义一个函数组件 function Greeting({ name }) { // 使用JSX来渲染组件的UI return ( <div> Hello, {name}! </div> ); } // 在另一个组件或应用中使用Greeting组件 function App() { return ( <div className="App"> <Greeting name="Alice" /> <Greeting name="Bob" /> </div> ); } export default App;
生命周期,指的是一个组件从其创建到销毁的整个过程。(React里面,只有类组件有,函数组件没有生命周期)
在这个过程中,React为组件划分了多个不同的阶段,每个阶段都配备了专门的方法和用途。正确理解和运用React的生命周期,对于构建既稳定又易于维护的React应用来说,显得至关重要。
掌握并恰当应用这些生命周期方法,将使得我们的React应用更加健壮和高效。
下面是最新16.3版本后的生命周期函数:
挂载时,是指组件实例被创建,首次插入到页面的过程。主要涉及到四个方法:constructor
、render
和 componentDidMount
,还有16.3新增的 getDerivedStateFromProps
以下是使用这些方法的示例:
class MyComponent extends React.Component { constructor(props) { super(props); // 1、初始化state this.state = { data: props.initialData, // 假设从props中接收initialData }; } // 2、静态方法 static getDerivedStateFromProps(props, state) { // 当props变化时,根据新的props和当前的state更新state if (props.initialData !== state.data) { return { data: props.initialData, }; } // 如果没有变化,返回null表示不更新state return null; } componentDidMount() { // 3、组件挂载到DOM后执行,适合发起网络请求、订阅事件等操作 console.log('Component has been mounted!'); } render() { // 4、渲染组件 return ( <div> <h1>My Component</h1> <p>Data: {this.state.data}</p> </div> ); } } export default MyComponent;
以上例子,总结:
constructor(props)
:方法用于初始化组件的state,并绑定事件处理函数到组件实例上。getDerivedStateFromProps
:是一个静态方法,它在每次组件的props更新并且即将重新渲染前被调用。render
:用于渲染组件的UI。componentDidMount
:在组件挂载到DOM后立即执行。当React组件的props或state发生变化时,组件会经历更新阶段。在更新阶段,React会根据这些变化决定是否重新渲染组件,并调用相应的生命周期方法。
主要涉及这几个方法:getDerivedStateFromProps
、shouldComponentUpdate
、getSnapshotBeforeUpdate
和 componentDidUpdate
以下是一个例子,说明了React组件在更新时涉及的主要生命周期方法:
class MyComponent extends Component { constructor(props) { super(props); this.state = { count: 0, prevCount: null, }; } static getDerivedStateFromProps(props, state) { // 根据props更新state,比如初始化state或者响应props的变化 if (props.initialCount !== state.count) { return { count: props.initialCount, prevCount: state.count, }; } return null; } shouldComponentUpdate(nextProps, nextState) { // 根据props或state的变化来决定是否重新渲染组件 // 这里我们简单地比较count是否变化 return nextState.count !== this.state.count; } getSnapshotBeforeUpdate(prevProps, prevState) { // 在DOM更新之前获取一些信息 // 假设我们要获取滚动位置 const scrollPosition = this.listRef.scrollTop; return { scrollPosition, }; } componentDidUpdate(prevProps, prevState, snapshot) { // DOM更新后,使用snapshot中的信息 if (snapshot && snapshot.scrollPosition !== undefined) { this.listRef.scrollTop = snapshot.scrollPosition; } // 假设我们还需要比较prevCount和currentCount if (prevState.prevCount !== null && prevState.prevCount !== this.state.count) { console.log(`Count changed from ${prevState.prevCount} to ${this.state.count}`); } } handleIncrement = () => { this.setState((prevState) => ({ count: prevState.count + 1, prevCount: prevState.count, })); }; render() { return ( <div> <p>Count: {this.state.count}</p> <button onClick={this.handleIncrement}>Increment</button> <div ref={(element) => (this.listRef = element)} style={{ height: '200px', overflowY: 'scroll' }} > {/* Some long content here that causes scrolling */} </div> </div> ); } } export default MyComponent;
以上例子,总结:
getDerivedStateFromProps
用于根据传入的props(initialCount
)来初始化或更新组件的state。如果initialCount
与当前count
不同,它会返回一个新的state对象,其中包含更新后的 count
和旧的 count
值(prevCount
)。shouldComponentUpdate
是一个方法,用于根据props或state的变化来决定是否重新渲染组件。这里我们简单地比较了 nextState.count
和 this.state.count
,如果它们不同,则组件会重新渲染。getSnapshotBeforeUpdate
在DOM更新之前被调用,它返回一个对象,该对象在 componentDidUpdate
的第三个参数中可用。这里我们获取了滚动列表的滚动位置。componentDidUpdate
在组件更新后被调用,并且接收上一个props、上一个state和getSnapshotBeforeUpdate
返回的snapshot作为参数。我们使用snapshot中的滚动位置来恢复滚动位置,同时比较 prevCount
和 this.state.count
来记录变化。卸载时阶段指的是组件从DOM中被完全移除时。
例如在类组件中,componentWillUnmount
是一个在组件卸载及销毁之前直接调用的生命周期方法。你可以在这个方法中执行任何必要的清理操作,例如取消网络请求、清除定时器、解除事件监听器等。
class MyComponent extends React.Component { componentDidMount() { // 设置定时器 this.timer = setInterval(() => { console.log('This runs every second'); }, 1000); } componentWillUnmount() { // 清除定时器 clearInterval(this.timer); } render() { return <div>MyComponent</div>; } } export default MyComponent;
在上面的例子中,componentDidMount
中设置了一个定时器,而 componentWillUnmount
中则清除了这个定时器,以确保在组件卸载时不会继续执行定时器的回调。
Hooks 放下一篇文章里,这里字已经水的差不多了
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/406265
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。