十道前端面试题第【07】篇
2021-05-19 本文已影响0人
夏海峰
1、字节跳动三面之React面试
- 什么是虚拟DOM?
- 类组件和函数组件之间有什么区别?
- React中的refs作用是什么?
- 在React中如何处理事件
- 什么是受控组件?
- 为什么不直接更新state状态?
- 描述Flux与MVC?
- React context是什么?
- React Fiber是什么?
2、描述 Diff运算过程,如何比较两个虚拟DOM的差异?
- React官方对 Diff运算过程的说明 :本文描述了在实现 React 的 “diffing” 算法过程中所作出的设计决策,以保证组件更新可预测,且在繁杂业务场景下依然保持应用的高性能。
3、伪代码封装 react-redux 库的connect
函数
export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) {
return function wrapWithConnect(WrappedComponent) {
class Connect extends Component {
constructor(props, context) {
// 从祖先Component处获得store
this.store = props.store || context.store
this.stateProps = computeStateProps(this.store, props)
this.dispatchProps = computeDispatchProps(this.store, props)
this.state = { storeState: null }
// 对stateProps、dispatchProps、parentProps进行合并
this.updateState()
}
shouldComponentUpdate(nextProps, nextState) {
// 进行判断,当数据发生改变时,Component重新渲染
if (propsChanged || mapStateProducedChange || dispatchPropsChanged) {
this.updateState(nextProps)
return true
}
}
componentDidMount() {
// 改变Component的state
this.store.subscribe(() = {
this.setState({
storeState: this.store.getState()
})
})
}
render() {
// 生成包裹组件Connect
return (
<WrappedComponent {...this.nextState} />
)
}
}
Connect.contextTypes = {
store: storeShape
}
return Connect;
}
}
4、从React的角度,有哪些性能优化的策略。
类组件中的优化手段:
- 使用纯组件
PureComponent
作为基类。 - 使用
shouldComponentUpdate
生命周期函数来自定义渲染逻辑。
函数式组件中的优化手段:
- 使用
React.memo
高阶函数包装组件,React.memo
可以实现类似于shouldComponentUpdate
或者PureComponent
的效果 - 使用
useMemo
精细化的管控,useMemo
控制的则是是否需要重复执行某一段逻辑,而React.memo
控制是否需要重渲染一个组件 - 使用
useCallBack
。
其他方式:
- 在列表需要频繁变动时,使用唯一 id 作为 key,而不是数组下标。
- 必要时通过改变 CSS 样式隐藏显示组件,而不是通过条件判断显示隐藏组件。
- 使用 Suspense 和 lazy 进行懒加载
5、有哪些定义React组件的方式
# 函数式组件
const PureComponent = (props) => (
<div>
//use props
</div>
)
# 类组件
class StatefulComponent extends Component {
constructor(props) {
super(props);
this.state = { }
}
render() {
return ();
}
}
# 容器组件
var UserListContainer = React.createClass({
getInitialState: function() {
return {
users: []
}
},
render: function() {
return (<UserList users={this.state.users} />);
}
})
# 高阶组件
const HigherOrderComponent = (WrappedComponent) => {
return class WrapperComponent extends Component {
render() {
<WrappedComponent />
}
}
}
# Render Callback组件
class RenderCallbackCmp extends React.Component {
constructor(props) {
super(props);
this.state = {
msg: "hello"
};
}
render() {
return this.props.children(this.state.msg);
}
}
const ParentComponent = () =>(
<RenderCallbackCmp>
{msg =><div>{msg}</div>}
</RenderCallbackCmp>
)
6、React中组件间通信,有哪些办法?
- 父子组件通信
- 自定义事件
- 使用 context 上下文
- 使用 redux 状态管理
7、谈一谈 React Hooks API
什么Hooks?Hooks有什么用?常用的Hooks有哪些?
- React官方之 Hooks简介
- useCallback 和 useMemo 类似计算属性的功能,它们只是语法不同而已。
- useRef 模拟使用 Refs特性。
- 自定义Hooks是基于useState/useEffect/useContext的封装
- 自定义Hooks是一种逻辑复用的策略
- 自定义Hooks的命名,必须以 use 开头。
自定义 useTitle 改变文档页面的 title
import { useEffect } from 'react'
const useTitle = (title) => {
useEffect(() => {
document.title = title
}, [])
return
}
export default useTitle
封装 useReducer 使用 Redux状态管理工具
function useReducer(reducer, initialState) {
const [state, setState] = useState(initialState);
function dispatch(action) {
const nextState = reducer(state, action);
setState(nextState);
}
return [state, dispatch];
}
// 使用 useReducer
function Todos() {
const [todos, dispatch] = useReducer(todosReducer, [])
function handleAddClick(text) {
dispatch({ type: 'add', text })
}
}
社区里面还有很多好用的自定义Hooks
使用上下文和自定义Hooks实现国际化
import React, { useContext } from 'react'
const LangContext = React.createContext()
export function useLang() {
return useContext(LangContext)
}
export const LangProvider = LangContext.Provider
# App.jsx
<LangProvider value={qfLang}>
<Layout />
</LangProvider>
8、React技术栈中,有哪些代码复用的技巧?
9、高阶组件有哪些应用场景?
高阶组件 不是组件,是 一个把某个组件转换成另一个组件的 函数。高阶组件的主要作用是 代码复用。高阶组件是 装饰器模式在 React 中的实现。
10、React路由相关
- 路由的查询参数和动态路由,有什么区别?
- withRouter 有什么用?
- 路由之代码分割的原理是什么?如何实现路由代码分割?
- 常用的路由 Hooks 有哪些?
- 路由如何实现鉴权验证?
- 对比 vue-router 和 react-router-dom 在概念上有哪些异同?
本周结束,下周继续!!!