React 面试题
参考答案请查阅《React-Notes》
React
基础概念
-
React 中Element 与Component 的区别是? -
为何在
JSX 或者TSX 的文件首部需要引入React ? -
猜想一下,
React DevTools 是如何监听React 的状态变化? -
调用
setState 之后发生了什么? -
React 中Element 与Component 的区别是? -
在什么情况下你会优先选择使用
Class Component 而不是Functional Component ? -
React 中keys 的作用是什么? -
如果你创建了类似于下面的
Twitter
元素,那么它相关的类定义是啥样子的?
<Twitter username="tylermcginnis33">
{(user) => (user === null ? <Loading /> : <Badge info={user} />)}
</Twitter>
-
Controlled Component 与Uncontrolled Component 之间的区别是什么? -
在生命周期中的哪一步你应该发起
AJAX 请求? -
shouldComponentUpdate 的作用是啥以及为何它这么重要? -
如何告诉
React 它应该编译生产环境版本? -
为什么我们需要使用
React 提供的Children API 而不是JavaScript 的map ? -
概述下
React 中的事件处理逻辑? -
createElement 与cloneElement 的区别是什么? -
传入
setState 函数的第二个参数的作用是什么?
函数式组件& Hooks
-
Hooks 函数式组件与类组件相比各有何优劣?为什么useCallback 中会存在所谓闭包冻结的现象? -
为什么
Hooks 不可在条件语句中使用? -
在类组件的
setState 中,我们经常会通过setState 的callback 来等待状态更新完毕后执行一些操作,那么在Hooks 中应该如何实现?
库与框架
-
在
Antd 中如何实现主题切换的特性,如何在单个项目中打包多个不同版本的Antd ? -
在
Antd 中,如何实现表单的异步校验?如何将某个表单的数据存放到Redux 中?
内部实现
- 调用
setState 之后发生了什么?
简单而言,createElement
的调用组合。而
- 在什么情况下你会优先选择使用
Class Component 而不是Functional Component ?
在组件需要包含内部状态或者使用到生命周期函数的时候使用
React 中refs 的作用是什么?
ref
属性然后在回调函数中接受该元素在
class CustomForm 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>
);
}
}
上述代码中的input
域包含了一个ref
属性,该属性声明的回调函数会接收input
对应的this
指针以便在其他的类函数中使用。另外值得一提的是,
function CustomForm({ handleSubmit }) {
let inputElement;
return (
<form onSubmit={() => handleSubmit(inputElement.value)}>
<input type="text" ref={(input) => (inputElement = input)} />{" "}
<button type="submit">Submit</button>{" "}
</form>
);
}
React 中keys 的作用是什么?
render () {
return (
<ul>
{this.state.todoItems.map(({task, uid}) => {
return <li key={uid}>{task}</li>
})}
</ul>
)
}
在开发过程中,我们需要保证某个元素的
- 如果你创建了类似于下面的
Twitter
元素,那么它相关的类定义是啥样子的?
<Twitter username="tylermcginnis33">
{(user) => (user === null ? <Loading /> : <Badge info={user} />)}
</Twitter>
import React, { Component, PropTypes } from "react";
import fetchUser from "twitter";
// fetchUser take in a username returns a promise
// which will resolve with that username's data.
class Twitter extends Component {
// finish this
}
如果你还不熟悉回调渲染模式props.children
进行调用:
import React, { Component, PropTypes } from "react";
import fetchUser from "twitter";
class Twitter extends Component {
state = {
user: null,
};
static propTypes = {
username: PropTypes.string.isRequired,
};
componentDidMount() {
fetchUser(this.props.username).then((user) => this.setState({ user }));
}
render() {
return this.props.children(this.state.user);
}
}
这种模式的优势在于将父组件与子组件解耦和,父组件可以直接访问子组件的内部状态而不需要再通过Badge
替换为Profile
,我们可以轻易地修改下回调函数即可:
<Twitter username="tylermcginnis33">
{(user) => (user === null ? <Loading /> : <Profile info={user} />)}
</Twitter>
Controlled Component 与Uncontrolled Component 之间的区别是什么?
username
变量值并没有存放到username
变量值时,我们应当调用setState
函数进行修改。
class ControlledForm extends Component {
state = {
username: "",
};
updateUsername = (e) => {
this.setState({
username: e.target.value,
});
};
handleSubmit = () => {};
render() {
return (
<form onSubmit={this.handleSubmit}>
{" "}
<input
type="text"
value={this.state.username}
onChange={this.updateUsername}
/>
<button type="submit">Submit</button>{" "}
</form>
);
}
}
而非受控组件
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>
);
}
}
竟然非受控组件看上去更好实现,我们可以直接从
- 在生命周期中的哪一步你应该发起
AJAX 请求?
我们应当将
-
React 下一代调和算法Fiber 会通过开始或停止渲染的方式优化应用性能,其会影响到componentWillMount 的触发次数。对于componentWillMount 这个生命周期函数的调用次数会变得不确定,React 可能会多次频繁调用componentWillMount 。如果我们将AJAX 请求放到componentWillMount 函数中,那么显而易见其会被触发多次,自然也就不是好的选择。 -
如果我们将
AJAX 请求放置在生命周期的其他函数中,我们并不能保证请求仅在组件挂载完毕后才会要求响应。如果我们的数据请求在组件挂载之前就完成,并且调用了setState
函数将数据添加到组件状态中,对于未挂载的组件则会报错。而在componentDidMount 函数中进行AJAX 请求则能有效避免这个问题。 -
shouldComponentUpdate 的作用是啥以及为何它这么重要?
- 如何告诉
React 它应该编译生产环境版本?
通常情况下我们会使用
- 为什么我们需要使用
React 提供的Children API 而不是JavaScript 的map ?
props.children
并不一定是数组类型,譬如下面这个元素:
<Parent>
<h1>Welcome.</h1>
</Parent>
如果我们使用props.children.map
函数来遍历时会受到异常提示,因为在这种情况下props.children
是对象props.children
设置为数组,就像下面这个代码片:
<Parent>
<h1>Welcome.</h1> <h2>props.children will now be an array</h2>
</Parent>
这也就是我们优先选择使用React.Children.map
函数的原因,其已经将props.children
不同类型的情况考虑在内了。
- 概述下
React 中的事件处理逻辑
为了解决跨浏览器兼容性问题,
createElement 与cloneElement 的区别是什么?
- 传入
setState 函数的第二个参数的作用是什么?
该函数会在setState
函数调用完成并且组件开始重渲染的时候被调用,我们可以用该函数来监听渲染是否完成:
this.setState({ username: "tylermcginnis33" }, () =>
console.log("setState has finished and the component has re-rendered.")
);
- 下述代码有错吗?
this.setState((prevState, props) => {
return {
streak: prevState.streak + props.count,
};
});
这段代码没啥问题,不过只是不太常用罢了,详细可以参考