共计 7258 个字符,预计需要花费 19 分钟才能阅读完成。
2021 前端 react 面试题汇总
1. mobx 和 redux 有什么区别?
(1)共同点
- 为了解决状态管理混乱,无奈无效同步的问题对立保护治理利用状态;
- 某一状态只有一个可信数据起源(通常命名为 store,指状态容器);
- 操作更新状态形式对立,并且可控(通常以 action 形式提供更新状态的路径);
- 反对将 store 与 React 组件连贯,如 react-redux,mobx- react;
(2)区别 Redux 更多的是遵循 Flux 模式的一种实现,是一个 JavaScript 库,它关注点次要是以下几方面∶
-
Action∶ 一个 JavaScript 对象,形容动作相干信息,次要蕴含 type 属性和 payload 属性∶
o type∶ action 类型; o payload∶ 负载数据; 复制代码
- Reducer∶ 定义利用状态如何响应不同动作(action),如何更新状态;
-
Store∶ 治理 action 和 reducer 及其关系的对象,次要提供以下性能∶
o 保护利用状态并反对拜访状态(getState()); o 反对监听 action 的散发,更新状态(dispatch(action)); o 反对订阅 store 的变更(subscribe(listener)); 复制代码
- 异步流∶ 因为 Redux 所有对 store 状态的变更,都应该通过 action 触发,异步工作(通常都是业务或获取数据工作)也不例外,而为了不将业务或数据相干的工作混入 React 组件中,就须要应用其余框架配合治理异步工作流程,如 redux-thunk,redux-saga 等;
Mobx 是一个通明函数响应式编程的状态治理库,它使得状态治理简略可伸缩∶
- Action∶定义扭转状态的动作函数,包含如何变更状态;
- Store∶ 集中管理模块状态(State)和动作(action)
- Derivation(衍生)∶ 从利用状态中派生而出,且没有任何其余影响的数据
比照总结:
- redux 将数据保留在繁多的 store 中,mobx 将数据保留在扩散的多个 store 中
- redux 应用 plain object 保留数据,须要手动解决变动后的操作;mobx 实用 observable 保留数据,数据变动后主动解决响应的操作
- redux 应用不可变状态,这意味着状态是只读的,不能间接去批改它,而是应该返回一个新的状态,同时应用纯函数;mobx 中的状态是可变的,能够间接对其进行批改
- mobx 相对来说比较简单,在其中有很多的形象,mobx 更多的应用面向对象的编程思维;redux 会比较复杂,因为其中的函数式编程思维把握起来不是那么容易,同时须要借助一系列的中间件来解决异步和副作用
- mobx 中有更多的形象和封装,调试会比拟艰难,同时后果也难以预测; 而 redux 提供可能进行工夫回溯的开发工具,同时其纯函数以及更少的形象,让调试变得更加的容易
2. Redux 和 Vuex 有什么区别,它们的独特思维
(1)Redux 和 Vuex 区别
- Vuex 改良了 Redux 中的 Action 和 Reducer 函数,以 mutations 变动函数取代 Reducer,无需 switch,只需在对应的 mutation 函数里扭转 state 值即可
- Vuex 因为 Vue 主动从新渲染的个性,无需订阅从新渲染函数,只有生成新的 State 即可
- Vuex 数据流的程序是∶View 调用 store.commit 提交对应的申请到 Store 中对应的 mutation 函数 ->store 扭转(vue 检测到数据变动主动渲染)
艰深点了解就是,vuex 弱化 dispatch,通过 commit 进行 store 状态的一次更变;勾销了 action 概念,不用传入特定的 action 模式进行指定变更;弱化 reducer,基于 commit 参数间接对数据进行转变,使得框架更加繁难;
(2)独特思维
- 单—的数据源
- 变动能够预测
实质上∶ redux 与 vuex 都是对 mvvm 思维的服务,将数据从视图中抽离的一种计划。
3. Redux 中间件是怎么拿到 store 和 action? 而后怎么解决?
redux 中间件实质就是一个函数柯里化。redux applyMiddleware Api 源码中每个 middleware 承受 2 个参数,Store 的 getState 函数和 dispatch 函数,别离取得 store 和 action,最终返回一个函数。该函数会被传入 next 的下一个 middleware 的 dispatch 办法,并返回一个接管 action 的新函数,这个函数能够间接调用 next(action),或者在其余须要的时刻调用,甚至基本不去调用它。调用链中最初一个 middleware 会承受实在的 store 的 dispatch 办法作为 next 参数,并借此完结调用链。所以,middleware 的函数签名是({getState,dispatch})=> next => action。
4. Redux 中的 connect 有什么作用
connect 负责连贯 React 和 Redux
(1)获取 state
connect 通过 context 获取 Provider 中的 store,通过 store.getState()
获取整个 store tree 上所有 state
(2)包装原组件
将 state 和 action 通过 props 的形式传入到原组件外部 wrapWithConnect 返回—个 ReactComponent 对 象 Connect,Connect 重 新 render 内部传入的原组件 WrappedComponent,并把 connect 中传入的 mapStateToProps,mapDispatchToProps 与组件上原有的 props 合并后,通过属性的形式传给 WrappedComponent
(3)监听 store tree 变动
connect 缓存了 store tree 中 state 的状态,通过以后 state 状态 和变更前 state 状态进行比拟,从而确定是否调用 this.setState()
办法触发 Connect 及其子组件的从新渲染
5. React Hooks 解决了哪些问题?
React Hooks 次要解决了以下问题:
(1)在组件之间复用状态逻辑很难
React 没有提供将可复用性行为“附加”到组件的路径(例如,把组件连贯到 store)解决此类问题能够应用 render props 和 高阶组件。然而这类计划须要从新组织组件构造,这可能会很麻烦,并且会使代码难以了解。由 providers,consumers,高阶组件,render props 等其余形象层组成的组件会造成“嵌套天堂”。只管能够在 DevTools 过滤掉它们,但这阐明了一个更深层次的问题:React 须要为共享状态逻辑提供更好的原生路径。
能够应用 Hook 从组件中提取状态逻辑,使得这些逻辑能够独自测试并复用。Hook 使咱们在无需批改组件构造的状况下复用状态逻辑。这使得在组件间或社区内共享 Hook 变得更便捷。
(2)简单组件变得难以了解
在组件中,每个生命周期经常蕴含一些不相干的逻辑。例如,组件经常在 componentDidMount 和 componentDidUpdate 中获取数据。然而,同一个 componentDidMount 中可能也蕴含很多其它的逻辑,如设置事件监听,而之后需在 componentWillUnmount 中革除。互相关联且须要对照批改的代码被进行了拆分,而齐全不相干的代码却在同一个办法中组合在一起。如此很容易产生 bug,并且导致逻辑不统一。
在少数状况下,不可能将组件拆分为更小的粒度,因为状态逻辑无处不在。这也给测试带来了肯定挑战。同时,这也是很多人将 React 与状态治理库联合应用的起因之一。然而,这往往会引入了很多抽象概念,须要你在不同的文件之间来回切换,使得复用变得更加艰难。
为了解决这个问题,Hook 将组件中互相关联的局部拆分成更小的函数(比方设置订阅或申请数据),而并非强制依照生命周期划分。你还能够应用 reducer 来治理组件的外部状态,使其更加可预测。
(3)难以了解的 class
除了代码复用和代码治理会遇到困难外,class 是学习 React 的一大屏障。咱们必须去了解 JavaScript 中 this 的工作形式,这与其余语言存在微小差别。还不能遗记绑定事件处理器。没有稳固的语法提案,这些代码十分冗余。大家能够很好地了解 props,state 和自顶向下的数据流,但对 class 却束手无策。即使在有教训的 React 开发者之间,对于函数组件与 class 组件的差别也存在一致,甚至还要辨别两种组件的应用场景。
为了解决这些问题,Hook 使你在非 class 的状况下能够应用更多的 React 个性。从概念上讲,React 组件始终更像是函数。而 Hook 则拥抱了函数,同时也没有就义 React 的精力准则。Hook 提供了问题的解决方案,无需学习简单的函数式或响应式编程技术
6. 为什么 React 并不举荐优先思考应用 Context?
- Context 目前还处于试验阶段,可能会在前面的发行版本中有很大的变动,事实上这种状况曾经产生了,所以为了防止给今后降级带来大的影响和麻烦,不倡议在 app 中应用 context。
- 只管不倡议在 app 中应用 context,然而独有组件而言,因为影响范畴小于 app,如果能够做到高内聚,不毁坏组件树之间的依赖关系,能够思考应用 context
- 对于组件之间的数据通信或者状态治理,无效应用 props 或者 state 解决,而后再思考应用第三方的成熟库进行解决,以上的办法都不是最佳的计划的时候,在思考 context。
- context 的更新须要通过 setState()触发,然而这并不是很牢靠的,Context 反对跨组件的拜访,然而如果两头的子组件通过一些办法不影响更新,比方 shouldComponentUpdate() 返回 false 那么不能保障 Context 的更新肯定能够应用 Context 的子组件,因而,Context 的可靠性须要关注
7. React 中什么是受控组件和非控组件?
(1)受控组件 在应用表单来收集用户输出时,例如<input><select><textearea>
等元素都要绑定一个 change 事件,当表单的状态发生变化,就会触发 onChange 事件,更新组件的 state。这种组件在 React 中被称为 受控组件,在受控组件中,组件渲染出的状态与它的 value 或 checked 属性绝对应,react 通过这种形式打消了组件的部分状态,使整个状态可控。react 官网举荐应用受控表单组件。
受控组件更新 state 的流程:
- 能够通过初始 state 中设置表单的默认值
- 每当表单的值发生变化时,调用 onChange 事件处理器
- 事件处理器通过事件对象 e 拿到扭转后的状态,并更新组件的 state
- 一旦通过 setState 办法更新 state,就会触发视图的从新渲染,实现表单组件的更新
受控组件缺点: 表单元素的值都是由 React 组件进行治理,当有多个输入框,或者多个这种组件时,如果想同时获取到全副的值就必须每个都要编写事件处理函数,这会让代码看着很臃肿,所以为了解决这种状况,呈现了非受控组件。
(2)非受控组件 如果一个表单组件没有 value props(单选和复选按钮对应的是 checked props)时,就能够称为非受控组件。在非受控组件中,能够应用一个 ref 来从 DOM 取得表单值。而不是为每个状态更新编写一个事件处理程序。
React 官网的解释:
要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你能够应用 ref 来从 DOM 节点中获取表单数据。因为非受控组件将实在数据贮存在 DOM 节点中,所以在应用非受控组件时,有时候反而更容易同时集成 React 和非 React 代码。如果你不介意代码好看性,并且心愿疾速编写代码,应用非受控组件往往能够缩小你的代码量。否则,你应该应用受控组件。
例如,上面的代码在非受控组件中接管单个属性:
class NameForm extends React.Component {constructor(props) {super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {alert('A name was submitted:' + this.input.value);
event.preventDefault();}
render() {
return (<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={(input) => this.input = input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
复制代码
总结: 页面中所有输出类的 DOM 如果是现用现取的称为非受控组件,而通过 setState 将输出的值保护到了 state 中,须要时再从 state 中取出,这里的数据就受到了 state 的管制,称为受控组件。
8. React 中 refs 的作用是什么?有哪些利用场景?
Refs 提供了一种形式,用于拜访在 render 办法中创立的 React 元素或 DOM 节点。Refs 应该审慎应用,如下场景应用 Refs 比拟适宜:
- 解决焦点、文本抉择或者媒体的管制
- 触发必要的动画
- 集成第三方 DOM 库
Refs 是应用 React.createRef()
办法创立的,他通过 ref
属性附加到 React 元素上。要在整个组件中应用 Refs,须要将 ref
在构造函数中调配给其实例属性:
class MyComponent extends React.Component {constructor(props) {super(props)
this.myRef = React.createRef()}
render() {return <div ref={this.myRef} />
}
}
复制代码
因为函数组件没有实例,因而不能在函数组件上间接应用 ref
:
function MyFunctionalComponent() {return <input />;}
class Parent extends React.Component {constructor(props) {super(props);
this.textInput = React.createRef();}
render() {
// 这将不会工作!return (<MyFunctionalComponent ref={this.textInput} />
);
}
}
复制代码
但能够通过闭合的帮忙在函数组件外部进行应用 Refs:
function CustomTextInput(props) {
// 这里必须申明 textInput,这样 ref 回调才能够援用它
let textInput = null;
function handleClick() {textInput.focus();
}
return (
<div>
<input
type="text"
ref={(input) => {textInput = input;}} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
);
}
复制代码
留神:
- 不应该适度的应用 Refs
-
ref
的返回值取决于节点的类型:
- 当
ref
属性被用于一个一般的 HTML 元素时,React.createRef()
将接管底层 DOM 元素作为他的current
属性以创立ref
。 - 当
ref
属性被用于一个自定义的类组件时,ref
对象将接管该组件已挂载的实例作为他的current
。
- 当
-
当在父组件中须要拜访子组件中的
ref
时可应用传递 Refs 或回调 Refs。9. 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 (<div onClick={this.handleClick}> You {text} this. Click to toggle. </div> ); } } ReactDOM.render( <LikeButton />, document.getElementById('example') );
构造函数用来新建父类的 this 对象;子类必须在 constructor 办法中调用 super 办法;否则新建实例时会报错;因为子类没有本人的 this 对象,而是继承父类的 this 对象,而后对其进行加工。如果不调用 super 办法;子类就得不到 this 对象。** 留神:**
- constructor () 必须配上 super(), 如果要在 constructor 外部应用 this.props 就要 传入 props , 否则不必
- JavaScript 中的 bind 每次都会返回一个新的函数, 为了性能等思考, 尽量在 constructor 中绑定事件
### 10. React.forwardRef 是什么?它有什么作用?React.forwardRef 会创立一个 React 组件,这个组件可能将其承受的 ref 属性转发到其组件树下的另一个组件中。这种技术并不常见,但在以下两种场景中特地有用:- 转发 refs 到 DOM 组件
- 在高阶组件中转发 refs