-
1.React组建之间如何通讯
-
父子组件通信(props/$emit)
-
父组件通过props向子组件传递数据,子组件通过$emit事件向父组件通信,props只能是父子件向子组件传递数据,使得父子组件直接形成一个向下的单项数据流,子组件不能直接修改props数据,只能通知父组件来修改。
-
$emit绑定一个自定义事件,可以将参数传递给父组件;父组件中则通过v-on注册监听事件同时接收参数
-
跨级组件通信 (provide/inject)
- 这种方式是通过依赖注入的方法实现组件(可跨级通信)依赖注入所提供的属性是飞响应似的
- provide:用来发送数据或方法
- inject:用来接收数据或方法
- ref/$refs在父子组件中通过ref可以获取子组件实例,通过实例来访问子组件的属性和方法
-
2.React组建生命周期
-
挂载阶段(Mounting):这些方法在组件被创建并插入DOM时被调用。
constructor()
:构造函数,在组件被创建时调用,用于初始化组件的状态和绑定方法。static getDerivedStateFromProps(props, state)
:在组件实例化和接收新的props时调用,用于根据props更新state。render()
:渲染方法,负责返回组件的JSX表示。componentDidMount()
:在组件挂载到DOM后调用,通常用于发起网络请求或订阅数据。
-
更新阶段(Updating):这些方法在组件重新渲染时被调用,通常由props或state的改变触发。
static getDerivedStateFromProps(props, state)
:在更新阶段也可以调用,用于根据新的props更新state。shouldComponentUpdate(nextProps, nextState)
:决定组件是否需要重新渲染,可以通过返回false
来阻止不必要的渲染。render()
:重新渲染组件。getSnapshotBeforeUpdate(prevProps, prevState)
:在更新之前获取DOM快照,通常与componentDidUpdate
一起使用。componentDidUpdate(prevProps, prevState, snapshot)
:在组件更新完成后调用,通常用于处理DOM更新后的操作。
-
卸载阶段(Unmounting):这些方法在组件从DOM中移除时被调用。
componentWillUnmount()
:在组件卸载前调用,通常用于清理定时器、取消订阅等操作。
3.React发起ajax应该在哪个生命周期
在React中,发起AJAX请求或任何其他的异步操作通常在componentDidMount
生命周期方法中进行。这确保了当你的异步操作完成并调用this.setState
时,组件已经挂载到DOM中,从而避免了因组件未挂载而产生的潜在错误。
import React, { Component } from 'react';
import axios from 'axios';
class DataFetchingComponent extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: true,
error: null
};
}
componentDidMount() {
axios.get('https://api.example.com/data')
.then(response => {
this.setState({ data: response.data, isLoading: false });
})
.catch(error => {
this.setState({ error, isLoading: false });
});
}
render() {
const { data, isLoading, error } = this.state;
if (isLoading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
return (
<div>
{data.map(item => (
<div key={item.id}>{item.name}</div>
))}
</div>
);
}
}
export default DataFetchingComponent;
在这个示例中,我们使用了axios
库来发起HTTP请求。当请求成功时,我们更新组件的状态来显示获取到的数据;当请求失败时,我们更新状态来显示错误信息。
总之,componentDidMount
是发起AJAX请求的合适位置,因为它确保了请求完成时组件已经挂载到DOM中
4.什么是纯函数
纯函数(Pure Function)是函数式编程中的一个重要概念,它具有以下两个主要特性:
-
相同的输入始终产生相同的输出:纯函数的输出完全由其输入决定,不受外部状态的影响。这意味着,如果你多次使用相同的输入调用纯函数,它将始终返回相同的结果,不会有随机性或副作用。
-
没有副作用:纯函数不会修改任何外部状态或产生其他可观察的副作用。它不会改变全局变量、修改传入的参数,也不会执行与计算结果无关的操作,如文件写入、网络请求等。它的唯一目的是根据输入计算输出。
纯函数的这两个特性使得它们在函数式编程中具有重要的地位,因为它们更容易推理、测试和组合。由于纯函数不依赖于外部状态,可以更容易实现并行计算和缓存结果。
示例:
# 纯函数的例子
def add(a, b):
return a + b
# 非纯函数的例子(有副作用)
total = 0
def addToTotal(x):
global total
total += x
在上面的例子中,add
函数是纯函数,因为它只依赖于输入参数 a
和 b
,并返回它们的和,没有修改任何外部状态。而 addToTotal
函数是非纯函数,因为它修改了外部状态 total
。
使用纯函数有助于提高代码的可维护性和可测试性,因为它们减少了不确定性和副作用。
5.react类组件的setState是同步操作还是异步操作
在 React 类组件中,setState
通常是异步操作,而不是同步操作。这意味着当你调用 setState
时,React 不会立即更新组件的状态,而是将更新任务放入更新队列中,然后在稍后的某个时间点执行更新。
React 之所以采用异步更新的方式,是为了优化性能和避免不必要的重复渲染。当多次调用 setState
时,React 可能会合并这些更新操作,然后一次性进行更新,以减少渲染的次数。
但需要注意的是,React 在某些情况下可能会执行同步更新。例如,在事件处理程序中调用 setState
时,React 会尝试进行同步更新,以确保在事件处理程序完成后,状态已经更新。但这种同步更新的行为是有条件的,不应该依赖于它来编写代码,因为未来的 React 版本可能会进行改变。
如果你需要在状态更新后执行某些操作,可以使用 setState
的回调函数或在生命周期方法(如 componentDidUpdate
)中进行处理,以确保在状态已经更新后执行相关逻辑。
示例:
// 异步更新状态
this.setState({ count: this.state.count + 1 });
// 使用回调函数在状态更新后执行操作
6.什么是受控组件、什么是非受控组件
this.setState({ count: this.state.count + 1 }, () => {
console.log('状态已更新');
});
1.受控组件
受控组件(Controlled Components)是指在React中,组件的状态(通常是表单元素的值)由React管理和控制的组件。这意味着组件的状态值是存储在React组件的state
中,并且通过props
和事件处理函数来更新和控制这些状态值。通常,受控组件用于处理用户输入的表单元素,如文本框、复选框、单选框等。
受控组件的主要特点包括:
-
状态存储在组件的state中: 受控组件的状态值通常存储在组件的
state
属性中,这使得React可以追踪和管理这些状态。 -
使用props传递值: 初始值通过
props
传递给组件,并且组件通过props
接收新的值。 -
通过事件处理函数更新状态: 用户输入的改变会触发事件,例如
onChange
事件,然后通过事件处理函数来更新组件的状态。这个事件处理函数通常会将新的值设置到组件的state
中,然后React会重新渲染组件。
以下是一个受控文本框(<input>
元素)的示例
import React, { Component } from 'react';
class ControlledInput extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: '' // 初始化输入值为空
};
}
handleChange = (event) => {
// 当文本框的值改变时触发
this.setState({ inputValue: event.target.value }); // 更新state
}
render() {
return (
<div>
<input
type="text"
value={this.state.inputValue} // 使用state作为值
onChange={this.handleChange} // 使用事件处理函数更新state
/>
<p>输入的值是: {this.state.inputValue}</p>
</div>
);
}
}
export default ControlledInput;
inputValue
的值受React的控制,而不是直接从DOM中获取,这就是受控组件的核心概念。
2.非受控组件
非受控组件(Uncontrolled Components)是指在React中,组件的状态值不由React的state
管理和控制,而是直接由DOM元素自身管理。这意味着组件的值不受React的状态追踪和控制,而是通过DOM元素的引用直接访问或操作。
非受控组件的主要特点包括:
-
状态值由DOM元素管理: 非受控组件的状态值通常不存储在React的
state
中,而是由DOM元素自己管理。这使得React不知道或不追踪组件的值。 -
无需事件处理函数: 非受控组件通常不需要编写事件处理函数来更新状态,因为它们的状态是由DOM元素直接控制的。
-
通过
ref
引用DOM元素: 为了访问非受控组件的值,通常会使用React的ref
来引用DOM元素,然后直接操作DOM元素。
以下是一个非受控文本框(<input>
元素)的示例:
import React, { Component } from 'react';
class UncontrolledInput extends Component {
constructor(props) {
super(props);
this.inputRef = React.createRef(); // 创建一个ref来引用DOM元素
}
handleButtonClick = () => {
// 使用ref来获取DOM元素的值
alert('输入的值是: ' + this.inputRef.current.value);
}
render() {
return (
<div>
<input
type="text"
ref={this.inputRef} // 将ref绑定到DOM元素
/>
<button onClick={this.handleButtonClick}>显示值</button>
</div>
);
}
}
export default UncontrolledInput;
input
元素的值不受React的状态管理,而是通过ref
引用直接访问的。当按钮被点击时,通过this.inputRef.current.value
来获取输入框的值。
非受控组件通常在需要与非React代码集成或需要访问DOM元素的情况下使用,但应该谨慎使用,因为它们不利于React的状态管理和组件控制。在大多数情况下,推荐使用受控组件来更好地利用React的状态管理和一致性。
7.函数组件和class组件的区别
-
语法:
- 函数组件是用函数来定义的,通常使用ES6的箭头函数或普通函数。
- 类组件是使用ES6的类来定义的,它继承自React组件类。
-
状态(State):
- 在函数组件中,可以使用React的
useState
钩子来管理组件的状态。 - 在类组件中,可以使用
this.state
来管理组件的状态。
- 在函数组件中,可以使用React的
-
生命周期方法:
- 函数组件可以使用React的钩子函数,如
useEffect
来处理组件的生命周期事件,如组件挂载、更新、卸载等。 - 类组件有一系列生命周期方法,如
componentDidMount
、componentDidUpdate
和componentWillUnmount
等,用于处理生命周期事件。
- 函数组件可以使用React的钩子函数,如
-
代码复杂度:
- 通常情况下,函数组件相对于类组件来说更简洁,代码量较少,易于理解和维护。
- 类组件在包含许多生命周期方法和复杂逻辑的情况下可能会变得复杂。
-
性能:
- 函数组件通常比类组件具有更好的性能,因为它们没有额外的实例化和维护React组件类的开销。
- 但在某些情况下,类组件的性能可能更好,因为它们可以使用
shouldComponentUpdate
等方法来进行性能优化。
-
this关键字:
- 在函数组件中,通常不需要使用
this
关键字,因为函数组件没有实例。 - 在类组件中,需要使用
this
关键字来访问实例属性和方法。
- 在函数组件中,通常不需要使用
-
Hooks支持:
- 函数组件更容易使用React的Hooks,如
useState
、useEffect
、useContext
等。 - 类组件也可以使用Hooks,但需要一些额外的配置和注意事项。
- 函数组件更容易使用React的Hooks,如
。
8.react和vue的区别
-
生态系统和社区支持:
- React由Facebook维护,拥有庞大的社区支持和丰富的生态系统。这意味着有很多第三方库和工具可以与React集成,以及大量的文档和教程。
- Vue由一个开源社区维护,虽然社区庞大,但相对来说小一些。Vue也有很多扩展库和工具,但它们的数量和React相比较少。
-
语法和模板:
- React使用JSX(JavaScript XML)作为组件的声明方式,它将HTML和JavaScript混合在一起,使得组件的结构和逻辑更紧密地关联在一起。
- Vue使用单文件组件(SFCs),其中模板、脚本和样式都包含在一个文件中,这样可以更清晰地定义组件的结构、逻辑和样式。
-
状态管理:
- React没有内置的状态管理工具,但通常与Redux、Mobx等第三方状态管理库一起使用,以便更好地管理组件之间的状态共享。
- Vue内置了Vuex,一个专门用于状态管理的库,使得状态管理更加直观和集成。
-
学习曲线:
- 对于有JavaScript经验的开发者来说,React的学习曲线可能会更陡峭,因为它需要理解JSX和一些概念,如虚拟DOM。
- Vue的学习曲线相对较平缓,因为它的语法更接近传统的HTML和JavaScript。
-
性能:
- React使用虚拟DOM来提高性能,通过最小化DOM操作来减少重绘和重排。
- Vue也使用虚拟DOM,因此在性能方面与React类似。但是,性能的实际表现可能取决于具体的使用情况和优化策略。
9.react事件和DOM事件有什么区别
React事件和DOM事件有一些重要的区别,主要体现在事件处理方式和性能优化方面:
-
事件处理方式:
- React事件:React使用合成事件(SyntheticEvent)来处理事件。合成事件是React提供的一种封装了原生DOM事件的事件系统,它使得事件处理在不同浏览器中表现一致,并且可以通过React组件的props来传递事件处理函数。React事件处理函数通过调用
setState
来更新组件状态,触发重新渲染。 - DOM事件:DOM事件是原生浏览器事件,通过
addEventListener
等方法直接在DOM元素上注册事件处理函数。处理DOM事件通常需要直接操作DOM,而不是使用虚拟DOM。
- React事件:React使用合成事件(SyntheticEvent)来处理事件。合成事件是React提供的一种封装了原生DOM事件的事件系统,它使得事件处理在不同浏览器中表现一致,并且可以通过React组件的props来传递事件处理函数。React事件处理函数通过调用
-
性能优化:
- React事件:React的事件系统经过优化,合成事件会在合适的时机被批量处理,以提高性能。React还可以通过shouldComponentUpdate等机制来避免不必要的渲染,进一步提高性能。
- DOM事件:直接使用DOM事件处理函数时,可能需要手动优化性能。大量的DOM事件处理函数可能导致频繁的重排和重绘,从而影响性能。开发者需要自己实施性能优化策略,例如事件委托(event delegation)来减少事件处理函数的数量。
-
事件命名:
- React事件:React事件命名采用驼峰命名法,例如
onClick
、onKeyDown
等。 - DOM事件:DOM事件采用全小写字母,例如
click
、keydown
等。
- React事件:React事件命名采用驼峰命名法,例如
-
事件传递和冒泡:
- React事件:React事件是通过组件层次结构进行传递的,事件从顶层组件向下传递,然后再从下往上冒泡。这种事件传递方式可以更精确地控制事件的处理和阻止冒泡。
- DOM事件:DOM事件也有冒泡机制,但在React中,可以使用
e.stopPropagation()
来阻止合成事件的冒泡,而不是直接操作DOM事件。
10.redux、 react-redux、 redux-thunk、 redux-saga、redux-toolkit,它们之间的 区别是什么?
-
Redux:
- Redux是JavaScript状态管理库,不仅与React一起使用,还可以与其他前端框架或纯JavaScript一起使用。
- Redux提供了一个单一的全局状态存储,使得状态可预测且易于管理。
- Redux的核心概念包括store、actions和reducers,它们一起帮助管理应用程序的状态。
-
React-Redux:
- React-Redux是Redux的官方绑定库,专门为React设计,以便更容易地将Redux与React组件集成。
- 它提供了
<Provider>
组件来将Redux store注入整个React应用程序,并使用connect
函数将Redux状态与React组件连接起来。
-
Redux-Thunk:
- Redux-Thunk是一个Redux中间件,用于处理异步操作。
- 它允许您在Redux中分派函数而不仅仅是普通的action对象,使得处理异步操作(如API调用)更容易。
-
Redux-Saga:
- Redux-Saga是另一个用于处理副作用和异步操作的Redux中间件。
- 它使用生成器函数来定义异步流程,使得处理复杂的副作用更容易,并且具有更高的可测试性。
-
Redux-Toolkit:
- Redux-Toolkit是Redux官方提供的工具集,用于简化Redux的使用。
- 它包括
createSlice
用于定义reducers,configureStore
用于创建store,并提供其他实用功能来减少样板代码。
Redux是核心库,用于状态管理,React-Redux用于将Redux与React集成,Redux-Thunk和Redux-Saga是处理异步操作的中间件,而Redux-Toolkit是用于简化Redux使用的工具集。