web前端 React 框架面试200题(三)
面试题 65. 在使用 React Router时,如何获取当前页面的路由或浏览器中地址栏中的地址?
参考回答:
在当前组件的 props中,包含 location属性对象,包含当前页面路由地址信息,在 match中存储当前路由的参数等数据信息。可以直接通过 this .props使用它们
面试题 66. 简述React中什么是纯组件?
参考回答:
纯组件是可以编写的最简单和最快的组件。它们可以替换任何只有 render() 的组件。这些组件增强了代码的简单性和应用程序的性能。
面试题 67. 解释React Reducer的作用?
参考回答:
Reducers 是纯函数,它指定应用程序的状态如何响应 ACTION 变化。Reducers 通过接收之前的状态和动作来工作,然后它返回一个新状态。它根据操作的类型确定需要进行何种类型的更新,然后返回新值。 如果不需要做任何工作,它会按原样返回先前的状态
面试题 68. 请简述Redux 与 Flux 有何不同?
参考回答:
1.Redux中只有一个store,而Flux中有多个store来存储应用数据,并在store里面执行更新逻辑,当store变化的时候再通知controller-view更新自己的数据,Redux是将各个store整合成一个完整的store,并且可以根据这个store来得到完整的state,而且更新的逻辑也不再store中,而是在reducer(采用纯函数)中。
2.Redux没有Dispatcher这个概念。它使用的是reducer来进行事件的处理,reducer是一个纯函数(preState, action) => newState,在Redux应用中,可能有多个reducer,每一reducer来负责维护应用整体state树中某一部分,多个reducer通过combineReducers方法合成一个根reducer,来维护整个state
面试题 69. React 如何更新组件状态?
参考回答:
可以使用 this.setState() 更新组件的状态:
class MyComponent extends React.Component {
constructor() {
super();
this.state = {
name: 'Maxx',
id: '101'
}
}
render()
{
setTimeout(()=>{this.setState({name:'Jaeha', id:'222'})},2000)
return (
Hello {this.state.name}
Your Id is {this.state.id}
);
}
}
ReactDOM.render(
, document.getElementById('content')
);
面试题 70. React 中的箭头函数是什么?它是如何使用的?
参考回答:
箭头函数更多是用于编写函数表达式的简短语法。它们也被称为“胖箭头”(=>)函数。这些函数允许正确绑定组件的上下文,因为在 ES6 中自动绑定默认不可用。箭头函数在处理高阶函数时最有用。
登录后复制
//General way
render() {
return(
);
}
//With Arrow Function
render() {
return(
this.handleOnChange(e) } />
);
}
面试题 71. 详细阐述Redux有什么优势?
参考回答:
结果的可预测性—— 因为总是有一个真实的来源,即商店,关于如何将当前状态与应用程序的动作和其他部分同步,没有任何混淆。
可维护性——代码变得更容易维护,具有可预测的结果和严格的结构。
服务器端渲染—— 您只需要将在服务器上创建的商店传递到客户端。这对于初始渲染非常有用,并提供更好的用户体验,因为它优化了应用程序性能。
开发人员工具——从操作到状态更改,开发人员可以实时跟踪应用程序中发生的一切。
社区和生态系统 ——Redux 背后有一个庞大的社区,这使得它使用起来更加迷人。一个庞大的人才社区为图书馆的改进做出了贡献,并用它开发了各种应用程序。
易于测试 ——Redux 的代码主要是小、纯和隔离的函数。这使得代码可测试且独立。
组织——Redux 对代码的组织方式 非常精确,这使得当团队使用代码时代码更加一致和容易。
面试题 72. 解释为什么在React Router v4 中使用switch 关键字?
参考回答:
switch 是用来封装Router内部的多条路由的。当您只想显示要在多个定义的路由中呈现的单个路由时,使用 “switch”关键字 。 使用中的 标记将键入的 URL 与已定义的路由按顺序匹配。 当找到第一个匹配项时,它会呈现指定的路由。从而绕过其余 路线。
面试题 73. 编写代码实现如何 React.createElement ?
参考回答:
const element = (
Hello, world!
)
const element = React.createElement(
'h1', {
className: 'greeting'
}
,
'Hello, world!'
面试题 74. 请用源码解释React setState 调用的原理 ?
参考回答:
具体的执行过程如下(源码级解析):
首先调用了setState 入口函数,入口函数在这里就是充当一个分发器的角色,根据入参的不同,将其分发到不同的功能函数中去;
ReactComponent.prototype.setState = function (partialState, callback) {
this.updater.enqueueSetState(this, partialState);
if (callback) {
this.updater.enqueueCallback(this, callback, 'setState');
}
};
在 enqueueUpdate 方法中引出了一个关键的对象——batchingStrategy,该对象所具备的isBatchingUpdates 属性直接决定了当下是要走更新流程,还是应该排队等待;如果轮到执行,就调用 batchedUpdates 方法来直接发起更新流程。由此可以推测,batchingStrategy 或许正是 React 内部专门用于管控批量更新的对象。
function enqueueUpdate(component) {
ensureInjected();
// 注意这一句是问题的关键,isBatchingUpdates标识着当前是否处于批量创建/更新组件的阶段
if (!batchingStrategy.isBatchingUpdates) {
// 若当前没有处于批量创建/更新组件的阶段,则立即更新组件
batchingStrategy.batchedUpdates(enqueueUpdate, component);
return;
}
// 否则,先把组件塞入 dirtyComponents 队列里,让它“再等等”
dirtyComponents.push(component);
if (component._updateBatchNumber == null) {
component._updateBatchNumber = updateBatchNumber + 1;
}
}
注意:batchingStrategy 对象可以理解为“锁管理器”。这里的“锁”,是指 React 全局唯一的 isBatchingUpdates 变量,isBatchingUpdates 的初始值是 false,意味着“当前并未进行任何批量更新操作”。每当 React 调用 batchedUpdate 去执行更新动作时,会先把这个锁给“锁上”(置为 true),表明“现在正处于批量更新过程中”。当锁被“锁上”的时候,任何需要更新的组件都只能暂时进入 dirtyComponents 里排队等候下一次的批量更新,而不能随意“插队”。此处体现的“任务锁”的思想,是 React 面对大量状态仍然能够实现有序分批处理的基石
面试题 75. 简述shouldComponentUpdate 作用?为什么它很重要?
参考回答:
组件状态数据或者属性数据发生更新的时候,组件会进入存在期,视图会渲染更新。在生命周期方法 should ComponentUpdate中,允许选择退出某些组件(和它们的子组件)的和解过程。
和解的最终目标是根据新的状态,以最有效的方式更新用户界面。如果我们知道用户界面的某一部分不会改变,那么没有理由让 React弄清楚它是否应该更新渲染。通过在 shouldComponentUpdate方法中返回 false, React将让当前组件及其所有子组件保持与当前组件状态相同
面试题 76. 简述什么是 React Context?
参考回答:
Context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性
面试题 77. React中如何避免不必要的render?
参考回答:
React 基于虚拟 DOM 和高效 Diff 算法的完美配合,实现了对 DOM 最小粒度的更新。大多数情况下,React 对 DOM 的渲染效率足以业务日常。但在个别复杂业务场景下,性能问题依然会困扰我们。此时需要采取一些措施来提升运行性能,其很重要的一个方向,就是避免不必要的渲染(Render)。这里提下优化的点:
shouldComponentUpdate 和 PureComponent
在 React 类组件中,可以利用 shouldComponentUpdate或者 PureComponent 来减少因父组件更新而触发子组件的 render,从而达到目的。shouldComponentUpdate 来决定是否组件是否重新渲染,如果不希望组件重新渲染,返回 false 即可。
利用高阶组件
在函数组件中,并没有 shouldComponentUpdate 这个生命周期,可以利用高阶组件,封装一个类似 PureComponet 的功能
使用 React.memo
React.memo 是 React 16.6 新的一个 API,用来缓存组件的渲染,避免不必要的更新,其实也是一个高阶组件,与 PureComponent 十分类似,但不同的是, React.memo只能用于函数组件
面试题 78. 简述React- Router有几种形式?
参考回答:
有以下几种形式。
HashRouter,通过散列实现,路由要带#。
BrowerRouter,利用HTML5中 history API实现,需要服务器端支持,兼容性不是很好
面试题 79. 简述什么是 Children 属性 ?
参考回答:
在JSX表达式中,一个开始标签(比如)和一个关闭标签(比如)之间的内容会作为一个特殊的属性props.children被自动传递给包含着它的组件。
这个属性有许多可用的方法,包括 React.Children.map,React.Children.forEach, React.Children.count, React.Children.only,React.Children.toArray
面试题 80. 解释为什么调用 setState 而不是直接改变 state?
参考回答:
如果您尝试直接改变组件的状态,React 将无法得知它需要重新渲染组件。通过使用setState()方法,React 可以更新组件的UI。
另外,您还可以谈谈如何不保证状态更新是同步的。如果需要基于另一个状态(或属性)更新组件的状态,请向setState()传递一个函数,该函数将 state 和 props 作为其两个参数:
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
面试题 81. 请简述React父子组件的通信方式?
参考回答:
父组件向子组件通信:父组件通过 props 向子组件传递需要的信息。
// 子组件: Child
const Child = props =>{
return
{props.name}
}
// 父组件 Parent
const Parent = ()=>{
return
}
子组件向父组件通信:: props+回调的方式。
// 子组件: Child
const Child = props =>{
const cb = msg =>{
return ()=>{
props.callback(msg)
}
}
return (
<button onClick={cb("你好!")}>你好</button>
)
}
// 父组件 Parent
class Parent extends Component {
callback(msg){
console.log(msg)
}
render(){
return
}
}
面试题 82. 简述 state 更新流程 ?
参考回答:
shouldComponentUpdate: 当组件的 state 或 props 发生改变时,都会首先触发这个生命周期函数。它会接收两个参数:nextProps, nextState——它们分别代表传入的新 props 和新的 state 值。拿到这两个值之后,我们就可以通过一些对比逻辑来决定是否有 re-render(重渲染)的必要了。如果该函数的返回值为 false,则生命周期终止,反之继续;
注意:此方法仅作为性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生 bug。应该考虑使用内置的 PureComponent 组件,而不是手动编写 shouldComponentUpdate()
componentWillUpdate:当组件的 state 或 props 发生改变时,会在渲染之前调用 componentWillUpdate。componentWillUpdate 是 React16 废弃的三个生命周期之一。过去,我们可能希望能在这个阶段去收集一些必要的信息(比如更新前的 DOM 信息等等),现在我们完全可以在 React16 的 getSnapshotBeforeUpdate 中去做这些事;
componentDidUpdate:componentDidUpdate() 会在UI更新后会被立即调用。它接收 prevProps(上一次的 props 值)作为入参,也就是说在此处我们仍然可以进行 props 值对比
面试题 83. 简述React中的Portal是什么?
参考回答:
Portals 提供了一种很好的将子节点渲染到父组件以外的 DOM 节点的方式。
第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或碎片。
第二个参数(container)则是一个 DOM 元素。
ReactDOM.createPortal(child, container)
面试题 84. 解释 React 中 render() 的目的和作用 ?
参考回答:
每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如
<form>、<group>、<div>
等。此函数必须保持纯净,即必须每次调用时都返回相同的结果
面试题 85. React如何获取组件对应的DOM元素?
参考回答:
可以用ref来获取某个子节点的实例,然后通过当前class组件实例的一些特定属性来直接获取子节点实例。
ref有三种实现方法:
字符串格式:字符串格式,这是React16版本之前用得最多的,例如:
span
函数格式:ref对应一个方法,该方法有一个参数,也就是对应的节点实例,例如:
this.info = ele}>
createRef方法:React 16提供的一个API,使用React.createRef()来实现
面试题 86. 说明React16版本的reconciliation阶段和commit阶段是什么 ?
参考回答:
reconciliation阶段包含的主要工作是对current tree 和 new tree 做diff计算,找出变化部分。进行遍历、对比等是可以中断,歇一会儿接着再来。
commit阶段是对上一阶段获取到的变化部分应用到真实的DOM树中,是一系列的DOM操作。不仅要维护更复杂的DOM状态,而且中断后再继续,会对用户体验造成影响。在普遍的应用场景下,此阶段的耗时比diff计算等耗时相对短
面试题 87. 请说明React中getDefaultProps 的作用 ?
参考回答:
通过实现组件的getDefaultProps,对属性设置默认值(ES5的写法):
var ShowTitle = React.createClass({
getDefaultProps:function(){
return{
title : "React"
}
},
render : function(){
return
<h1>{this.props.title}</h1>
}
});
面试题 88. 简述React 组件中怎么做事件代理?它的原理是什么?
参考回答:
React基于Virtual DOM实现了一个SyntheticEvent层(合成事件层),定义的事件处理器会接收到一个合成事件对象的实例,它符合W3C标准,且与原生的浏览器事件拥有同样的接口,支持冒泡机制,所有的事件都自动绑定在最外层上。
在React底层,主要对合成事件做了两件事:
1 事件委派: React会把所有的事件绑定到结构的最外层,使用统一的事件监听器,这个事件监听器上维持了一个映射来保存所有组件内部事件监听和处理函数。
2 自动绑定: React组件中,每个方法的上下文都会指向该组件的实例,即自动绑定this为当前组件
面试题 89. 请简述React组件的构造函数的作用?
参考回答:
构造函数主要用于两个目的:
通过将对象分配给this.state来初始化本地状态
将事件处理程序方法绑定到实例上
所以,当在React class中需要设置state的初始值或者绑定事件时,需要加上构造函数,官方Demo:
class LikeButton extends React.Component {
constructor() {
super();
this.state = {
liked: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({liked: !this.state.liked});
}
render() {
const text = this.state.liked ? 'liked' : 'haven\'t liked';
return (
You {text} this. Click to toggle.
);
}
}
ReactDOM.render(
,
document.getElementById('example')
);
构造函数用来新建父类的this对象;子类必须在constructor方法中调用super方法;否则新建实例时会报错;因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法;子类就得不到this对象。
注意:
constructor () 必须配上 super(), 如果要在constructor 内部使用 this.props 就要 传入props , 否则不用
JavaScript中的 bind 每次都会返回一个新的函数, 为了性能等考虑, 尽量在constructor中绑定事件
面试题 90. 简述React Hooks在平时开发中需要注意的问题和原因 ?
参考回答:
(1)不要在循环,条件或嵌套函数中调用Hook,必须始终在 React函数的顶层使用Hook
这是因为React需要利用调用顺序来正确更新相应的状态,以及调用相应的钩子函数。一旦在循环或条件分支语句中调用Hook,就容易导致调用顺序的不一致性,从而产生难以预料到的后果。
(2)使用useState时候,使用push,pop,splice等直接更改数组对象的坑
使用push直接更改数组无法获取到新值,应该采用析构方式,但是在class里面不会有这个问题。代码示例:
function Indicatorfilter() {
let [num,setNums] = useState([0,1,2,3])
const test = () => {
// 这里坑是直接采用push去更新num
// setNums(num)是无法更新num的
// 必须使用num = [...num ,1]
num.push(1)
// num = [...num ,1]
setNums(num)
}
return (
测试
{num.map((item,index) => (
{item}
))}
)
}
class Indicatorfilter extends React.Component{
constructor(props:any){
super(props)
this.state = {
nums:[1,2,3]
}
this.test = this.test.bind(this)
}
test(){
// class采用同样的方式是没有问题的
this.state.nums.push(1)
this.setState({
nums: this.state.nums
})
}
render(){
let {nums} = this.state
return(
测试
{nums.map((item:any,index:number) => (
{item}
))}
)
}
}
(3)useState设置状态的时候,只有第一次生效,后期需要更新状态,必须通过useEffect
TableDeail是一个公共组件,在调用它的父组件里面,我们通过set改变columns的值,以为传递给TableDeail 的 columns是最新的值,所以tabColumn每次也是最新的值,但是实际tabColumn是最开始的值,不会随着columns的更新而更新:
const TableDeail = ({ columns,}:TableData) => {
const [tabColumn, setTabColumn] = useState(columns)
}
// 正确的做法是通过useEffect改变这个值
const TableDeail = ({ columns,}:TableData) => {
const [tabColumn, setTabColumn] = useState(columns)
useEffect(() =>{setTabColumn(columns)},[columns])
}
(4)善用useCallback
父组件传递给子组件事件句柄时,如果我们没有任何参数变动可能会选用useMemo。但是每一次父组件渲染子组件即使没变化也会跟着渲染一次。
(5)不要滥用useContext
可以使用基于 useContext 封装的状态管理工具。
面试题 91. 在React中组件的this.state和setState有什么区别?
参考回答:
this.state通常是用来初始化state的,this.setState是用来修改state值的。如果初始化了state之后再使用this.state,之前的state会被覆盖掉,如果使用this.setState,只会替换掉相应的state值。所以,如果想要修改state的值,就需要使用setState,而不能直接修改state,直接修改state之后页面是不会更新的。
面试题 92. 如何配置 React-Router 实现路由切换?
参考回答:
(1)使用 组件
路由匹配是通过比较 的 path 属性和当前地址的 pathname 来实现的。当一个 匹配成功时,它将渲染其内容,当它不匹配时就会渲染 null。没有路径的 将始终被匹配。
// when location = { pathname: '/about' }
About
}
/> // renders
Contact
}
/> // renders null
Always
}
/> // renders
(2)结合使用 组件和 组件
用于将 分组。
Home
}
/>
About
}
/>
Contact
}
/>
不是分组 所必须的,但他通常很有用。 一个 会遍历其所有的子 元素,并仅渲染与当前地址匹配的第一个元素。
(3)使用 、 、 组件
组件来在你的应用程序中创建链接。无论你在何处渲染一个 ,都会在应用程序的 HTML 中渲染锚()。
Home
// Home
是一种特殊类型的 当它的 to属性与当前地址匹配时,可以将其定义为"活跃的"。
// location = { pathname: '/react' }
React
// React
当我们想强制导航时,可以渲染一个,当一个渲染时,它将使用它的to属性进行定向
面试题 93. 简述React中class定义的组件和function定义的组件的区别?
参考回答:
function定义的组件没有this指向的问题
class定义的组件有自己的局部状态(this.state)和自己的生命周期函数,function定义的组件是无状态组件,但是在16.8之后可以用hooks(useEffect)来模拟组件的局部状态和生命周期。
官方建议使用function来定义组件,写法简单,并且便于理解。
面试题 94. 简述React中hooks是如何模拟组件的生命周期的?
参考回答:
componentDidMount
function Example() {
useEffect(() => console.log('mounted'), []);
return null;
}
复制代码
useEffect 拥有两个参数,第一个参数作为回调函数会在浏览器布局和绘制完成后调用,因此它不会阻碍浏览器的渲染进程。 第二个参数是一个数组
当数组存在并有值时,如果数组中的任何值发生更改,则每次渲染后都会触发回调。
当它不存在时,每次渲染后都会触发回调。
当它是一个空列表时,回调只会被触发一次,类似于 componentDidMount。
componentDidUpdate
useEffect(() => console.log('count updated'),[count]);
复制代码
componentWillUnmount
useEffect(() => {
return () => {
console.log('will unmount');
}
}
, []);
当在 useEffect 的回调函数中返回一个函数时,这个函数会在组件卸载前被调用。我们可以在这里面清除定时器或事件监听器。
面试题 95. 简述什么是React中的错误边界?
参考回答:
React16.X中引入了错误边界(Error Boundaries)概念。
它可以捕获它的子组件中产生的错误,类似于try-catch,只不过是以react组件的形式来实现的。
有了错误边界,即使某个组件的结果有错误,整个React程序挂载也不会被挂掉。只有出错的那个组件会显示一个后备界面,而整个程序仍然完全正常运行。
这里的componentDidCatch()函数使用方法和JavaScript中的catch {}代码块差不多,但只能用于组件。只有类组件才可以成为错误边界。
在componentDidCatch()函数内部我们把hasError状态设置为true。然后在渲染方法中检查那个状态。如果出错状态是真,就渲染后备界面;如果是false就把想渲染的React组件界面当作子组件界面渲染出来。
尽管如此,以下错误Error Boundaries依旧无法捕获:
1 事件错误
2 Error Boundaries本身的错误
3 异步代码
面试题 96. 叙述React如何使用Redux(使用流程) ?
参考回答:
1 在脚手架中安装react-redux
2 使用createStore去创建一个全局的store,用来保存所有的state,createStore接收一个reducer作为参数,你可以使用combineReducers传入多个reducer。
3 在reducer中,接收两个参数,第一个参数表示数据的初始状态,第二个参数表示action,并且reducer会返回一个新的对象作为数据,这样的话可以不进行原始对象的比较,性能会提高。
4 想要改变数据的话,就是view通过dispatch去派发一个action去执行相应的reducer,并且在store中进行更新,store改变的话,view就会重新渲染。
5 我们可能要使用react-redux中的connect和Provider方法 去关联我们的数据。Provider通过context上下文向子组件提供store,connect把redux中的数据和组件中的props做关联,这里用到的方法是mapStateToProps把store中的数据去映射到组件的props中,这样在组件中就可以通过props去访问到redux中的数据。
6 如果需要发送异步请求的话,还需要react-thunk插件,需要在creaceStore中做一个配置。
原文地址:https://blog.csdn.net/p445098355/article/details/140589603
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!