类组件和函数组件的区别
定义方式
类组件是通过ES6类语法来创建的,必须继承React.Component。函数组件就是普通的JS函数
状态和生命周期
类组件有内置的状态和生命周期,函数组件则是依靠React Hooks的useState和useEffect,使得函数组件才拥有自己的状态和生命周期
性能
函数组件在性能上优于类组件,因为没有实例化的过程,避免了内存消耗
useState
const [state, setState] = useState(initialState);
useState异步问题
在React中,useState
是一个用于状态管理的 Hook。如果你遇到了 useState
相关的异步问题,可能是因为你尝试在组件渲染后直接更新状态。React的状态更新机制是基于异步的,意味着状态的更新可能会在下一次渲染周期才会反映出来。
例如,你设置状态后立即尝试读取它,你可能会得到旧的值,因为状态更新可能还没有完成。
解决方法:更新的回调使用函数形式;使用useEffect()
const [count, setCount] = useState(0);
// 使用函数形式的setState
setCount(prevCount => prevCount + 1);
useEffect(() => {
// 在这里执行依赖于state变化之后的操作
}, [count]); // 依赖项数组确保只有在count变化时才会执行
useMemo和useCallback
useMemo:缓存的是一个计算结果
useMemo 是一个用于优化性能的 React Hook,它的主要作用是避免在每次渲染时都进行复杂的计算和重新创建对象。通过记住上一次的计算结果,只有在依赖项发生变化时才重新计算,从而提高性能
useCallback:缓存的是一个函数
useCallback 是一个用于优化性能的 React Hook,它的主要作用是避免在每次渲染时都重新创建函数。通过记住上一次创建的函数,只有在依赖项发生变化时才重新创建新的函数,从而提高性能
import React, { useState, useCallback, useMemo } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
// 使用useCallback优化回调函数
const handleClick = useCallback(() => {
console.log('Button clicked! Count:', count);
}, [count]);
// 使用useMemo优化计算结果
const doubledCount = useMemo(() => {
console.log('Calculating doubled count...');
return count * 2;
}, [count]);
return (
<div>
<button onClick={handleClick}>Click Me</button>
<p>Count: {count}</p>
<p>Doubled Count: {doubledCount}</p>
</div>
);
}
React.memo组件
React.memo
是 React 16.6 版本引入的一个高阶组件,用于避免不必要的重新渲染。当组件的 props 没有发生变化时,React.memo
可以帮助跳过该组件的渲染过程,从而提高性能。
import React, { memo, useState } from 'react';
const MyComponent = memo(function MyComponent(props) {
console.log('MyComponent rendering...');
return <div>{props.value}</div>;
});
function ParentComponent() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment</button>
<MyComponent value={count} />
</div>
);
}
在这个例子中,每当 ParentComponent 中的 count 状态变化时,MyComponent 都会被重新渲染。
但是,如果使用了 React.memo,只有当 count 值真正改变(即 MyComponent 的 props 发生变化)时,MyComponent 才会重新渲染
自定义比较函数
React.memo
还可以接受一个可选的比较函数作为第二个参数。这个比较函数用于自定义 props 的比较逻辑。默认情况下,React.memo
会执行浅比较来检查 props 是否发生变化
const areEqual = (prevProps, nextProps) => {
// 自定义比较逻辑
// 如果 props 没有变化,返回 true,否则返回 false
};
const MyComponent = memo(function MyComponent(props) {
// ...
}, areEqual);
useEffect
react提供了hooks,因此函数组件也可以用hooks进行状态管理并且也可以用useEffect模拟class组件的生命周期
useEffect的依赖项是做浅比较
useEffect第一个参数是一个回调函数,在依赖项发生变化的时候,会执行它,也被称为副作用函数。 可以在里面进行相应的生命周期阶段的操作,异步请求,设定计时器等,可以通过副作用函数的return来清除副作用,比如回收计时器
可以模拟三个生命周期函数,分别是componentDidMount,componentDidUpdate,componentWillUnMpunt
componentDidMount: 在组件挂载后立即执行的生命周期方法。可以使用空的依赖数组模拟此行为
useEffect(() => {
// componentDidMount 逻辑
}, []);
componentDidUpdate: 在组件更新后执行的生命周期方法。可以将需要监听的变量添加到依赖数组中,并在useEffect回调函数中处理更新逻辑
useEffect(() => {
// componentDidUpdate 逻辑
}, [variable1, variable2]);
componentWillUnmount: 在组件卸载之前执行的生命周期方法。可以在返回函数中定义清理逻辑。
useEffect(() => {
// componentDidMount 逻辑
return () => {
// componentWillUnmount 逻辑
};
}, []);
react组件props的默认值
如果一个组件没有传递props,但是组件使用这个属性的话,那么默认为undefined
设置默认值
class MyComponent extends React.Component {
render() {
return <div>{this.props.text}</div>; // 不给默认值显示undefined
}
}
MyComponent.defaultProps = {
text: '默认文本'
};
const MyComponent = ({ text }) => {
return <div>{text}</div>;
};
MyComponent.defaultProps = {
text: '默认文本'
};
propTypes校验
我们还可以使用 PropTypes 来定义组件的属性类型及设定默认值,确保传入的属性符合预期。也是一种对组件进行开发时的契约约束的好方法
import PropTypes from 'prop-types';
const MyComponent = ({ text }) => {
return <div>{text}</div>;
};
MyComponent.defaultProps = {
text: '默认文本'
};
MyComponent.propTypes = {
text: PropTypes.string
};
react中引入图片的方法
使用import语句
import React from 'react';
import myImage from './path/to/image.jpg';
function MyComponent() {
return <img src={myImage} alt="description" />;
}
使用require语句(使用较少)
import React from 'react';
function MyComponent() {
const myImage = require('./path/to/image.jpg');
return <img src={myImage} alt="description" />;
}
直接使用图片的url
import React from 'react';
function MyComponent() {
return <img src="https://example.com/path/to/image.jpg" alt="description" />;
}
react的受控组件
受控组件就是在react中,其值有react状态控制的表单元素,最常见的就是input组件
class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {inputValue: ''};
}
handleChange = (event) => {
this.setState({inputValue: event.target.value});
}
handleSubmit = (event) => {
alert('Submitted value: ' + this.state.inputValue);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Input:
<input
type="text"
value={this.state.inputValue}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
高阶组件
在业务开发中,虽然不掌握高阶组件也可以完成项目的开发,但是如果我们能够灵活地使用高阶组件,可以让项目代码变得更加优雅,同时增强代码的复用性和灵活性,提升开发效率,
个人理解就是vue组件封装中的插槽,适用于进行组件封装
react的render函数什么时候会被触发
- 当组件的state(状态)发生变化的时候
- 当组件的props发生变化的时候
- 当父组件的render函数被触发的时候,即使当前的props和state没有发生变化也会重新渲染
优化技巧:
- shouldcomponentUpdate:-这个生命周期方法可以让我们手动控制组件是否需要更新,它会在每次组件重清染之前调用,并通过返回true或fals 决定是否重新清染组件。这样可以比较新旧的props和state,自定义条件来减少不必要的渲染
- React.memo:使用这个函数来提高性能,可以缓存组件,避免了不必要的渲染
react事件绑定
内联函数绑定
class MyComponent extends React.Component {
render() {
return (
<button onClick={() => this.handleClick()}>Click me</button>
);
}
handleClick() {
console.log('Button clicked');
}
}
优点:方便,代码简洁
缺点:每次渲染都会创建新的函数实例,可能会影响性能
解决方法:使用usCallback钩子优化事件处理函数,会返回一个记忆函数,减少不必要的重新渲染
import React, { useCallback } from 'react';
const MyFunctionComponent = () => {
const handleClick = useCallback(() => {
console.log('Button clicked');
}, []);
return (
<button onClick={handleClick}>Click me</button>
);
};
类绑定
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('Button clicked');
}
render() {
return (
<button onClick={this.handleClick}>Click me</button>
);
}
}
构造函数绑定
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.handleClick = () => {
console.log('Button clicked');
};
}
render() {
return (
<button onClick={this.handleClick}>Click me</button>
);
}
}
React中Component和PureComponent的区别
在React中,Component和Purecomponent主要区别在于
Purecomponent 实现了浅比较(shalow comparison)来决定是否重新渲染组件,而普通的component 在每次更新状态或接收新属性时都会重新渲染。
- 浅比较:PureComponent依赖浅比较来决定是否重新渲染,如果props和state都是简单的,不可变的数据结构,那么使用pureComponent就会减少渲染次数,浅比较只是比较第一层的属性,无法深度检测对象属性的变化
- 不可变数据:开发中建议使用不可变数据结构,使用Object.freeze来保证数据不会被意外修改
- 性能优化策略:合理使用useMemo和useCallback钩子来避免性能瓶颈