面试 React 框架八股文十问十答第五期
作者:程序员小白条,个人博客
相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!
⭐点赞⭐收藏⭐不迷路!⭐文章来源地址https://www.toymoban.com/news/detail-802320.html
1)对 React context 的理解
React Context 是 React 中用于跨多层级传递数据的一种方式,可以让组件之间共享一些全局的状态,而不需要通过一层层的手动传递 props。Context 提供了一个在组件树中传递数据的方法,避免了 props 层层传递的繁琐。
Context 主要包含两部分:
-
React.createContext
: 创建一个 Context 对象,该对象包含了Provider
和Consumer
组件。 -
<MyContext.Provider>
: 在组件树中的某个位置,用于提供共享的数据,通过value
属性传递数据。 -
<MyContext.Consumer>
: 在组件树中的某个位置,用于订阅Provider
提供的数据。
2)为什么React并不推荐优先考虑使用Context?
尽管 React Context 提供了一种在组件之间共享状态的方式,但并不是在所有情况下都建议优先考虑使用 Context。以下是一些原因:
- 降低组件的可复用性: 使用 Context 可能使组件与特定的上下文绑定,导致组件在其他上下文中难以复用。
- 不容易追踪数据流: 当数据通过 Context 传递时,可能会变得不够明确和难以追踪。相比于显式地通过 props 传递,Context 的数据流不够明显,可能使得代码更难理解。
- 全局状态管理库更适用: 对于大型应用,使用专门的全局状态管理库(如 Redux 或 MobX)可能更合适,因为它们提供了更强大的状态管理和调试工具。
虽然 Context 是一个强大的工具,但在一些场景下,更传统的 props 传递仍然是更简单、清晰、可维护的选择。
3)React中什么是受控组件和非控组件?
-
受控组件(Controlled Components): 受控组件是指其状态(如输入框的值)完全受 React 控制的组件。通常,受控组件通过 props 接收其当前值,并通过回调函数通知父组件状态的变化。例如,
<input>
元素的值由 React 的状态管理。class ControlledComponent extends React.Component { constructor(props) { super(props); this.state = { value: '' }; } handleChange = (event) => { this.setState({ value: event.target.value }); }; render() { return <input type="text" value={this.state.value} onChange={this.handleChange} />; } }
-
非控组件(Uncontrolled Components): 非控组件是指其状态不受 React 管理,而是由 DOM 自身来处理。在非控组件中,状态通常通过 DOM 的原生方式管理,而不是通过 React 的状态。
class UncontrolledComponent extends React.Component { inputRef = React.createRef(); handleSubmit = () => { alert(`Input Value: ${this.inputRef.current.value}`); }; render() { return ( <div> <input type="text" ref={this.inputRef} /> <button onClick={this.handleSubmit}>Submit</button> </div> ); } }
在上述例子中,UncontrolledComponent
中的输入框的值是由 DOM 自身管理的,而不是通过 React 的状态管理。
4)React中refs的作用是什么?有哪些应用场景?
Refs 是 React 提供的一种访问 DOM 元素或类组件实例的方式。Refs 的主要作用是在 React 中访问、操作和修改 DOM 元素,以及获取或调用类组件的实例方法。
应用场景包括:
-
访问 DOM 元素: 使用
ref
属性可以获取组件渲染后对应的 DOM 元素,从而进行 DOM 操作。class MyComponent extends React.Component { constructor(props) { super(props); } componentDidMount() { // 访问 DOM 元素 console.log(this.myRef.current); } render() { return <div ref={this.myRef}>Hello, World!</div>; } }
-
获取或调用类组件的实例方法: 可以使用
ref
获取类组件的实例,从而调用组件中的方法。class MyComponent extends React.Component { myMethod() { console.log('Method called'); } render() { return <div>Hello, World!</div>; } } class ParentComponent extends React.Component { constructor(props) { super(props); this.myComponentRef = React.createRef(); } componentDidMount() { // 获取 MyComponent 的实例并调用方法 this.myComponentRef.current.myMethod(); } render() { return <MyComponent ref={this.myComponentRef} />; } }
5)React组件的构造函数有什么作用?它是必须的吗?
React 组件的构造函数 是类组件中的一个特殊方法,它主要用于进行初始化工作,设置初始状态、绑定方法等。构造函数是类组件的一部分,不是必须的,但在需要进行一些初始化操作时是很有用的。
主要作用包括:
-
初始化状态(state): 在构造函数中可以使用
this.state
初始化组件的状态,为组件提供初始值。class MyComponent extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } // ... }
-
绑定方法: 在构造函数中可以使用
bind
方法绑定事件处理函数,确保它们在后
6)React.forwardRef是什么?它有什么作用?
React.forwardRef 是一个高阶函数,用于向子组件转发父组件中的 ref。通过 forwardRef
,父组件可以直接访问子组件的 DOM 节点或实例。这对于封装组件并保持 ref 传递的纯粹性非常有用。
const ChildComponent = React.forwardRef((props, ref) => {
return <input ref={ref} />;
});
const ParentComponent = () => {
const childRef = React.createRef();
return <ChildComponent ref={childRef} />;
};
在上面的例子中,ChildComponent
接收了 forwardRef
函数,父组件 ParentComponent
可以通过 childRef
直接访问 ChildComponent
内部的 input
元素。
7)类组件与函数组件有什么异同?
类组件和函数组件都是 React 组件的两种主要形式,它们有以下异同:
相同点:
- 都可以用来定义 UI 组件。
- 可以拥有状态(通过
useState
或this.state
)和生命周期方法(在类组件中)。
不同点:
-
语法: 类组件是使用 ES6 类语法定义的,而函数组件是使用函数语法定义的。函数组件通常更简洁。
// 类组件 class MyComponent extends React.Component { // ... } // 函数组件 function MyComponent() { // ... }
-
状态管理: 类组件使用
this.state
来管理状态,而函数组件使用useState
钩子。// 类组件 class MyComponent extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } // ... } // 函数组件 function MyComponent() { const [count, setCount] = React.useState(0); // ... }
-
生命周期: 类组件具有生命周期方法(如
componentDidMount
、componentDidUpdate
等),而函数组件可以使用useEffect
钩子来模拟生命周期行为。
8)React setState 调用的原理
在 React 中,setState
是用于更新组件状态的方法。调用 setState
会触发一系列更新流程,其原理如下:
-
合并状态(Merge State):
setState
可以接收一个对象或一个函数。当接收一个对象时,React 会将该对象与当前状态进行浅合并。如果接收一个函数,该函数会接收先前的状态和当前的 props 作为参数,然后返回一个新的状态对象。// 对象形式 this.setState({ count: this.state.count + 1 }); // 函数形式 this.setState((prevState, props) => ({ count: prevState.count + 1 }));
-
触发更新流程:
setState
调用会触发组件的重新渲染。React 会通过调度机制将更新放入队列中,然后在适当的时候执行更新。 -
异步更新:
setState
并不会立即改变组件的状态,而是将更新放入队列中。这是因为 React 会对一连串的setState
调用进行合并,然后再进行一次更新。这样可以避免不必要的重复渲染。
9)React setState 调用之后发生了什么?是同步还是异步?
setState
调用之后,React 并不会立即执行状态更新,而是采用异步的方式进行。这是因为 React 会将 setState
调用加入到队列中,而不是立即执行更新操作。
由于异步更新,连续多次调用 setState
不会立即触发多次渲染,而是将这些调用合并成一次更新,以提高性能。
React 提供了一个 callback
参数,可以在状态更新完成并且组件重新渲染后执行回调函数。这可以用于在状态更新完成后执行一些操作。
this.setState({ count: this.state.count + 1 }, () => {
console.log('State updated and component re-rendered.');
});
10)React中的setState批量更新的过程是什么?
React 中的 setState
批量更新是指在一个事件循环内将多个 setState
调用合并成一次更新,以提高性能。这个过程可以分为以下几个步骤:
-
触发更新: 当调用
setState
时,React 会将更新任务添加到队列中,而不是立即执行更新。 -
合并更新: React 会对队列中的更新任务进行合并,以减少重复渲染的次数。如果有多个
setState
调用,React 会将它们合并成一个更新任务。 - 异步更新: React 采用异步的方式执行更新,即在当前事件循环结束后再进行更新。这样可以确保在一次事件循环内将所有更新任务合并并只触发一次重新渲染。
-
生命周期方法调用: 如果组件在更新时有相关的生命周期方法(如
componentDidUpdate
),这些方法将在更新完成后被调用。
这个批量更新的过程使得 React 在性能上更高效,因为它减少了重复渲染的次数。但需要注意的是,并非所有情况都会触发批量更新,例如在 setTimeout
、setInterval
、事件处理函数等异步场景中,setState
会以同步方式执行,不会进行批量更新。
开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system
已 300 + Star!文章来源:https://www.toymoban.com/news/detail-802320.html
⭐点赞⭐收藏⭐不迷路!⭐
到了这里,关于面试 React 框架八股文十问十答第五期的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!