React 灵魂 23 问,你能答对几个?
1、setState 是异步还是同步?
合成事件中是异步 钩子函数中的是异步 原生事件中是同步 setTimeout中是同步
2、聊聊 react@16.4 + 的生命周期

3、useEffect(fn, []) 和 componentDidMount 有什么差异?
useEffect
会捕获 props
和 state
。所以即便在回调函数里,你拿到的还是初始的 props
和 state
。如果想得到“最新”的值,可以使用ref
。4、hooks 为什么不能放在条件判断里?
setState
为例,在 react 内部,每个组件(Fiber)的 hooks 都是以链表的形式存在 memoizeState
属性中:
setState
,链表就会执行 next 向后移动一步。如果将 setState
写在条件判断中,假设条件判断不成立,没有执行里面的 setState
方法,会导致接下来所有的 setState
的取值出现偏移,从而导致异常发生。5、fiber 是什么?
requestIdleCallback
的机制来做异步 diff。但是之前数据结构不支持这样的实现异步 diff,于是 React 实现了一个类似链表的数据结构,将原来的 递归diff 变成了现在的 遍历diff,这样就能做到异步可更新了。
6、聊一聊 diff 算法


7、调用 setState 之后发生了什么?
在 setState
的时候,React 会为当前节点创建一个updateQueue
的更新列队。然后会触发 reconciliation
过程,在这个过程中,会使用名为 Fiber 的调度算法,开始生成新的 Fiber 树, Fiber 算法的最大特点是可以做到异步可中断的执行。然后 React Scheduler
会根据优先级高低,先执行优先级高的节点,具体是执行doWork
方法。在 doWork
方法中,React 会执行一遍updateQueue
中的方法,以获得新的节点。然后对比新旧节点,为老节点打上 更新、插入、替换 等 Tag。当前节点 doWork
完成后,会执行performUnitOfWork
方法获得新节点,然后再重复上面的过程。当所有节点都 doWork
完成后,会触发commitRoot
方法,React 进入 commit 阶段。在 commit 阶段中,React 会根据前面为各个节点打的 Tag,一次性更新整个 dom 元素。
8、为什么虚拟dom 会提高性能?
9、错误边界是什么?它有什么用?
class ErrorBoundary extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 可以将错误日志上报给服务器
console.log('组件奔溃 Error', error);
console.log('组件奔溃 Info', errorInfo);
}
render() {
if (this.state.hasError) {
// 你可以自定义降级后的 UI 并渲染
return this.props.content;
}
return this.props.children;
}
}
10、什么是 Portals?
ReactDOM.createPortal(child, container)
11、React 组件间有那些通信方式?
父组件向子组件通信
子组件向父组件通信
跨层级通信
Context
进行通信,createContext
创建上下文, useContext
使用上下文。import React, { createContext, useContext } from 'react';
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
const ThemeContext = createContext(themes.light);
function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
);
}
export default App;
12、React 父组件如何调用子组件中的方法?
>= react@16.8
),可以使用 useRef
和 useImperativeHandle
:const { forwardRef, useRef, useImperativeHandle } = React;
const Child = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
getAlert() {
alert("getAlert from Child");
}
}));
return <h1>Hi</h1>;
});
const Parent = () => {
const childRef = useRef();
return (
<div>
<Child ref={childRef} />
<button onClick={() => childRef.current.getAlert()}>Click</button>
</div>
);
};
>= react@16.4
),可以使用 createRef
:const { Component } = React;
class Parent extends Component {
constructor(props) {
super(props);
this.child = React.createRef();
}
onClick = () => {
this.child.current.getAlert();
};
render() {
return (
<div>
<Child ref={this.child} />
<button onClick={this.onClick}>Click</button>
</div>
);
}
}
class Child extends Component {
getAlert() {
alert('getAlert from Child');
}
render() {
return <h1>Hello</h1>;
}
}
13、React有哪些优化性能的手段?
类组件中的优化手段
PureComponent
作为基类。React.memo
高阶函数包装组件。shouldComponentUpdate
生命周期函数来自定义渲染逻辑。方法组件中的优化手段
useMemo
。useCallBack
。其他方式
Suspense
和 lazy
进行懒加载,例如:import React, { lazy, Suspense } from "react";
export default class CallingLazyComponents extends React.Component {
render() {
var ComponentToLazyLoad = null;
if (this.props.name == "Mayank") {
ComponentToLazyLoad = lazy(() => import("./mayankComponent"));
} else if (this.props.name == "Anshul") {
ComponentToLazyLoad = lazy(() => import("./anshulComponent"));
}
return (
<div>
<h1>This is the Base User: {this.state.name}</h1>
<Suspense fallback={<div>Loading...</div>}>
<ComponentToLazyLoad />
</Suspense>
</div>
)
}
}
Suspense
用法可以参考官方文档14、为什么 React 元素有一个 $$typeof 属性?

// 服务端允许用户存储 JSON
let expectedTextButGotJSON = {
type: 'div',
props: {
dangerouslySetInnerHTML: {
__html: '/* 把你想的搁着 */'
},
},
// ...
};
let message = { text: expectedTextButGotJSON };
// React 0.13 中有风险
<p>
{message.text}
</p>
15、React 如何区分 Class组件 和 Function组件?
function isClass(func) {
return typeof func === 'function'
&& /^class\s/.test(Function.prototype.toString.call(func));
}
AComponent.prototype instanceof React.Component
16、HTML 和 React 事件处理有什么区别?
<button onclick='activateLasers()'>
<button onClick={activateLasers}>
<a href='#' onclick='console.log("The link was clicked."); return false;' />
preventDefault()
:function handleClick(event) {
event.preventDefault()
console.log('The link was clicked.')
}
17、什么是 suspense 组件?
const resource = fetchProfileData();
function ProfilePage() {
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails />
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline />
</Suspense>
</Suspense>
);
}
function ProfileDetails() {
// 尝试读取用户信息,尽管该数据可能尚未加载
const user = resource.user.read();
return <h1>{user.name}</h1>;
}
function ProfileTimeline() {
// 尝试读取博文信息,尽管该部分数据可能尚未加载
const posts = resource.posts.read();
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
18、为什么 JSX 中的组件名要以大写字母开头?
19、redux 是什么?
跨层级组件之间的数据传递变得很容易 所有对状态的改变都需要 dispatch,使得整个数据的改变可追踪,方便排查问题。
概念偏多,理解起来不容易 样板代码太多
20、react-redux 的实现原理?
react-redux
。21、reudx 和 mobx 的区别?
22、redux 异步中间件有什么什么作用?
function App() {
const onClick = () => {
dispatch({ type: 'LOADING', message: 'data is loading' })
fetch('dataurl').then(() => {
dispatch({ type: 'LOADED' })
});
}
return (<div>
<button onClick={onClick}>click</button>
</div>);
}
function fetchData(message: string) {
return (dispatch) => {
dispatch({ type: 'LOADING', message })
setTimeout(() => {
dispatch({ type: 'LOADED' })
}, 1000)
}
}
function App() {
const onClick = () => {
fetchData('data is loading')(dispatch)
}
return (<div>
<button onClick={onClick}>click</button>
</div>);
}
fetchData('data is loading')(dispatch)
这种写法有点奇怪,会增加开发者的心智负担。rudux-chunk
为例,将写法改为如下:function fetchData(message: string) {
return (dispatch) => {
dispatch({ type: 'LOADING', message })
setTimeout(() => {
dispatch({ type: 'LOADED' })
}, 1000)
}
}
function App() {
const onClick = () => {
- fetchData('data is loading')(dispatch)
+ dispatch(fetchData('data is loading'))
}
return (<div>
<button onClick={onClick}>click</button>
</div>);
}
23、redux 有哪些异步中间件?
作者:王玉略 https://zhuanlan.zhihu.com/p/304213203
在应用开发中,我为什么选择 Flutter 而不是 React Native ?
学学 React Native 并没有坏处 | 学习资料分享 02
点个『在看』支持下
评论