【React】相关题目总结
文章目录
1.什么是虚拟DOM?
一种概念和模式,真实DOM的内存表示,通过ReactDOM这种库和真实DOM进行同步、调和。
2.props和state的区别
都是JS对象
- props 是一个从
外部传进组件的参数
,主要作为就是从父组件向子组件传递数据
,它具有可读性和不变性,只能通过外部组件主动传入新的 props 来重新渲染子组件
,否则子组件的 props 以及展现形式不会改变。 - state 的主要作用是用于
组件保存、控制以及修改自己的状态
,它只能在 constructor中初始化
,它算是组件的私有属性
,不可通过外部访问和修改,只能通过组件内部的this.setState 来修改
,修改 state属性会导致组件的重新渲染
。
3.类组件和函数组件有什么区别?
都不能修改props;
React是单项数据流,子组件视图根据父组件的改变而更新;
- 类组件
属性 props 是外界传递过来的,状态 state 是组件本身的,状态可以在组件中任意修改组件的属性和状态改变都会更新视图。
例如:
class Welcome extends React.Component {
render() {
return (
<h1>Welcome { this.props.name }</h1>
);
}
}
ReactDOM.render(<Welcome name='react' />, document.getElementById('root'));
- 函数组件
函数组件接收一个单一的 props 对象并返回了一个React元素
function Welcome (props) {
return <h1>Welcome {props.name}</h1>
}
ReactDOM.render(<Welcome name='react' />,
document.getElementById('root'));
- 函数组件的性能比类组件的性能要高,因为类组件使用的时候要
实例化
,而函数组件直接执行函数取返回结果即可。为了提高性能,尽量使用函数组件。
4.refs
- 使用refs可以进行
DOM元素或者某个组件
的安全访问。 - 给一个元素进行
refs属性添加
,然后接收该元素在DOM树中的句柄
,这个值作为回调函数的第一个参数返回
。
例如下面代码中:input包含一个refs属性,然后回调函数获取input元素的内容用this绑定到类中,供其他类函数调用
。
class UnControlledForm extends Component {
handleSubmit = () => {
console.log("Input Value: ", this.input.value)
}
render () {
return (
<form onSubmit={this.handleSubmit}>
<input
type='text'
ref={(input) => this.input = input} />
<button type='submit'>Submit</button>
</form>
)
}
}
当然函数也可以通过闭包,比如下面定义了个inputElement,来模拟this暂存ref属性的回调函数获取的值。
function CustomForm ({handleSubmit}) {
let inputElement
return (
<form onSubmit={() => handleSubmit(inputElement.value)}>
<input
type='text'
ref={(input) => inputElement = input} />
<button type='submit'>Submit</button>
</form>
)
}
- 创建refs,通过在构造函数内部创建
this.refName = React.createRef();
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
5.什么是高阶组件?
高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。
这是从React的组成性质派生的一种模式,我们称它们为 “纯”组件, 因为它们可以接受任何动态提供的子组件
,但它们不会修改或复制
其输入组件的任何行为。
const EnhancedComponent = higherOrderComponent(WrappedComponent);
- 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧
- 高阶组件的参数为一个组件返回一个新的组件
- 组件是将 props 转换为 UI,而高阶组件是将组件转换为另一个组件
6.constructor中super与props参数一起使用的目的是什么?
- 在子类的构造函数constructor中,必须先调用
super(props)
,才能在构造函数内部用this.props
- 但是构造函数外面的
this.props
是都可以获取到值的
//使用props:
class MyComponent extends React.Component {
constructor(props) {
super(props);
console.log(this.props); // Prints { name: 'sudheer',age: 30 }
}
}
//不使用props:
class MyComponent extends React.Component {
constructor(props) {
super();
console.log(this.props); // Prints undefined
// But Props parameter is still available
console.log(props); // Prints { name: 'sudheer',age: 30 }
}
render() {
// No difference outside constructor
console.log(this.props) // Prints { name: 'sudheer',age: 30 }
}
}
7.什么是JSX
JSX即JavaScript XML
。一种在React组件内部构建标签的类XML语法
。JSX为react.js开发的一套语法糖,也是react.js的使用基础。React在不使用JSX的情况下一样可以工作,然而使用JSX可以提高组件的可读性
,因此推荐使用JSX。
- 优点
-
允许使用熟悉的语法来
定义 HTML 元素树
; -
提供更加
语义化
且移动的标签; -
程序结构更容易被
直观化
; -
抽象了 React Element 的创建
过程; -
可以随时
掌控 HTML 标签以及生成这些标签
的代码; -
是
原生的 JavaScript
。
8.React.createElement
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
等同于
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
9.受控组件和非受控组件
<input>, <textarea> , 和 <select>
这类表单元素会维持自身状态,并根据用户输入进行更新。但在React中,可变的状态通常保存在组件的状态属性中,并且只能用 setState() 方法进行更新。
- 非受react的控制的组件
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Demo1 extends Component {
render() {
return (
<input />
)
}
}
ReactDOM.render(<Demo1/>, document.getElementById('content'))
在这个最简单的输入框组件里,我们并没有干涉input中的value展示,即用户输入的内容都会展示在上面。
- 受控组件
既然通过设置input的value属性, 无法改变输入框值,那么我们把它和state结合在一起
,再绑定onChange事件
,实时更新value值就行了。
class Demo1 extends Component {
constructor(props) {
super(props);
this.state = {
value: props.value
}
}
handleChange(e) {
this.setState({
value: e.target.value
})
}
render() {
return (
<input value={this.state.value} onChange={e => this.handleChange(e)}/>
)
}
}
10.为什么不直接更新state状态?
我的理解是,因为之前已经初始化了组件的属性,就不能再去直接改变他了
,而能够改变这个属性值的办法就是通过state事件
,也就是在渲染后进行更新的时候。
//Wrong
This.state.message =”Hello world”;
//Correct
This.setState({message: ‘Hello World’});
11.ReactJS生命周期有哪些不同阶段?
初始化和渲染
1. 获取props初始值
组件类在声明时,会先调用getDefaultProps()
方法来获取默认props值,这个方法会且只会在声明组件类时调用一次
,这一点需要注意,它返回的默认props由所有实例共享。
2. 获取state事件
在组件被实例化之前,会先调用一次实例方法getInitialState()
方法,用于获取这个组件的初始state
。
3. 实例化之后渲染的准备工作
componentWillMount
方法会在生成虚拟DOM之前被调用,你可以在这里对组件的渲染做一些准备工作,比如计算目标容器尺寸然后修改组件自身的尺寸以适应目标容器
等。
4. render渲染
创建一个虚拟DOM
用来表示组件的结构。对于一个组件来说,render是唯一一个必须的方法。render方法需要满足这几点:
只能通过this.props或this.state访问数据
只能出现一个顶级组件
可以返回null、false或任何
React组件
不能对props、state或DOM进行修改
需要注意的是,render方法返回的是虚拟DOM
。
5. 渲染完成以后对DOM的后续操作
我们可能需要对DOM做一些操作,比如截屏、上报日志,或者初始化iScroll等第三方非React插件,可以在componentDidMount()方法
中做这些事情。当然,你也可以在这个方法里通过this.getDOMNode()方法最终生成DOM节点
,然后对DOM节点做爱做的事情,但需要注意做好安全措施,不要缓存
已经生成的DOM节点,因为这些DOM节点随时可能被替换掉,所以应该在每次用的时候去读取
。
组件被初始化完成后,它的状态会随着用户的操作、时间的推移、数据更新而产生变化,变化的过程是组件声明周期的另一部分——
更新
1. 根据相关改变预处理数据
当组件已经被初始化后组件调用者修改组件的属性
时,组件的componentWillReceiveProps()
方法会被调用,在这里,你可以对外部传入的数据进行一些预处理
,比如从props中读取数据写入state
。
2.判断是否必须更新,过滤无效渲染
默认情况下,组件调用者修改组件属性时,React会遍历
这个组件的所有子组件,进行“灌水”,将props从上到下一层一层传下去,并逐个执行更新操作,虽然React内部已经进行过很多的优化,这个过程是很快的,如果你追求极致性能或者你发现这个过程花费了太久时间,使用shouldComponentUpdate()
——
有时候,props发生了变化,但组件和子组件并不会因为这个props的变化而发生变化,打个比方,你有一个表单组件,你想要修改表单的name,同时你能够确信这个name不会对组件的渲染产生任何影响
,那么你可以直接在这个方法里return false来终止后续行为。这样就能够避免无效的虚拟DOM对比
了,对性能会有明显提升。
如果这个时候有同学仍然饥渴难耐,那么你可以尝试 不可变数据结构(用过mongodb的同学应该懂)。
3.更新的准备工作
组件在更新前,React会执行componentWillUpdate()方法,这个方法类似于前面看到的componentWillMount()方法,唯一不同的地方只是这个方法在执行的时候组件是已经渲染过的。需要注意的是,不可以在这个方法中修改props或state,如果要修改,应当在componentWillReceiveProps()中修改
。
4.对比虚拟DOM并替换
然后是渲染,React会拿这次返回的虚拟DOM和缓存中的虚拟DOM进行对比
,找出【最小修改点】,然后替换。
5.更新完成后
React会调用组件的componentDidUpdate方法,这个方法类似于前面的componentDidMount方法,你仍然可以在这里可以通过this.getDOMNode()方法取得最终的DOM节点。
销毁
12.React context是什么?
- 简单说就是,当你不想在组件树中通过逐层传递 props 或者 state 的方式来传递数据时,可以使用 Context 来实现 跨层级
的组件数据传递。 - 原来是这个样子的自上往下的数据流
- 在render的渲染时用上
this.content.data
可以直接跨组件数据传递
13.为什么类方法需要绑定?
在JavaScript中, this 的值取决于当前上下文
。在React类的组件方法中,开发人员通常希望引用组件的方法
,因此有必要 将 这些方法 绑定 到该实例。通常,这是在构造函数中完成的
,例如:
class SubmitButton extends React.Component {
constructor(props) {
super(props);
this.state = {
isFormSubmitted: false
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit() {
this.setState({
isFormSubmitted: true
});
}
render() {
return (
<button onClick={this.handleSubmit}>Submit</button>
)
}
}
14.React中的这三个点(…)是做什么的?
例如,如果this.props包含a:1和b:2,则
<Modal {...this.props} title='Modal heading' animation={false}>
与以下内容相同:
<Modal a={this.props.a} b={this.props.b} title='Modal heading' animation={false}>
扩展符号
不仅适用于该用例,而且对于创建具有现有对象的大多数(或全部)属性的新对象非常方便-在更新状态时会遇到很多问题,因为您无法修改状态值:
this.setState(prevState => {
return {foo: {...prevState.foo, a: "updated"}};
});