目录
[一、对componentWillReceiveProps 的理解](#一、对componentWillReceiveProps 的理解)
三、可以使用TypeScript写React应用吗?怎么操作?
[(1)如果还未创建 Create React App 项目](#(1)如果还未创建 Create React App 项目)
[(2)如果已经创建了 Create React App 项目,需要将 typescript 引入到已有项目中](#(2)如果已经创建了 Create React App 项目,需要将 typescript 引入到已有项目中)
四、React中constructor和getInitialState的区别?
六、为什么使用jsx的组件中没有看到使用react却需要引入react?
[七、HOC相比 mixins 有什么优点?](#七、HOC相比 mixins 有什么优点?)
[八、React 中的高阶组件运用了什么设计模式?](#八、React 中的高阶组件运用了什么设计模式?)
[十、Redux 请求中间件如何处理并发](#十、Redux 请求中间件如何处理并发)
[十一、Redux 中间件是怎么拿到store 和 action? 然后怎么处理?](#十一、Redux 中间件是怎么拿到store 和 action? 然后怎么处理?)
十一、React中的setState和replaceState的区别是什么?
一、对componentWillReceiveProps 的理解
该方法当 props 发生变化时执行,初始化 render 时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用 this.setState() 来更新你的组件状态,旧的属性还是可以通过 this.props 来获取,这里调用更新状态是安全的,并不会触发额外的 render 调用。
使用好处:在这个生命周期中,可以在子组件的render函数执行前获取新的props,从而更新子组件自己的state。 可以将数据请求放在这里进行执行,需要传的参数则从componentWillReceiveProps(nextProps)中获取。而不必将所有的请求都放在父组件中。于是该请求只会在该组件渲染时才会发出,从而减轻请求负担。componentWillReceiveProps在初始化render的时候不会执行,它会在Component接受到新的状态(Props)时被触发,一般用于父组件状态更新时子组件的重新渲染。
二、React.forwardRef是什么?它有什么作用?
React.forwardRef 会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。这种技术并不常见,但在以下两种场景中特别有用:
- 转发 refs 到 DOM 组件
- 在高阶组件中转发 refs
三、可以使用TypeScript写React应用吗?怎么操作?
(1)如果还未创建 Create React App 项目
- 直接创建一个具有 typescript 的 Create React App 项目:
TypeScript
npx create-react-app demo --typescript
(2)如果已经创建了 Create React App 项目,需要将 typescript 引入到已有项目中
- 通过命令将 typescript 引入项目:
javascript
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
- 将项目中任何 后缀名为 .js 的 JavaScript 文件重命名为 TypeScript 文件即后缀名为 .tsx(例如 src/index.js 重命名为 src/index.tsx )
四、React中constructor和getInitialState的区别?
两者都是用来初始化state的。前者是ES6中的语法,后者是ES5中的语法,新版本的React中已经废弃了该方法。
getInitialState是ES5中的方法,如果使用createClass方法创建一个Component组件,可以自动调用它的getInitialState方法来获取初始化的State对象
javascript
var APP = React.creatClass ({
getInitialState() {
return {
userName: 'hi',
userId: 0
};
}
})
React在ES6的实现中去掉了getInitialState这个hook函数,规定state在constructor中实现,如下:
javascript
Class App extends React.Component{
constructor(props){
super(props);
this.state={};
}
}
五、React的严格模式如何使用,有什么用处?
StrictMode 是一个用来突出显示应用程序中潜在问题的工具。与 Fragment 一样,StrictMode 不会渲染任何可见的 UI。它为其后代元素触发额外的检查和警告。
可以为应用程序的任何部分启用严格模式。例如:
javascript
import React from 'react';
function ExampleApplication() {
return (
<div>
<Header />
<React.StrictMode>
<div>
<ComponentOne />
<ComponentTwo />
</div>
</React.StrictMode>
<Footer />
</div>
);
}
在上述的示例中,不会对 Header 和 Footer 组件运行严格模式检查。但是,ComponentOne 和 ComponentTwo 以及它们的所有后代元素都将进行检查。
StrictMode 目前有助于:
- 识别不安全的生命周期
- 关于使用过时字符串 ref API 的警告
- 关于使用废弃的 findDOMNode 方法的警告
- 检测意外的副作用
- 检测过时的 context API
六、为什么使用jsx的组件中没有看到使用react却需要引入react?
本质上来说JSX是React.createElement(component, props, ...children)方法的语法糖。在React 17之前,如果使用了JSX,其实就是在使用React, babel 会把组件转换为 CreateElement 形式。在React 17之后,就不再需要引入,因为 babel 已经可以帮我们自动引入react。
七、HOC相比 mixins 有什么优点?
HOC 和 Vue 中的 mixins 作用是一致的,并且在早期 React 也是使用 mixins 的方式。但是在使用 class 的方式创建组件以后,mixins 的方式就不能使用了,并且其实 mixins 也是存在一些问题的,比如:
- 隐含了一些依赖,比如我在组件中写了某个 state 并且在 mixin 中使用了,就这存在了一个依赖关系。万一下次别人要移除它,就得去 mixin 中查找依赖。
- 多个 mixin 中可能存在相同命名的函数,同时代码组件中也不能出现相同命名的函数,否则就是重写了。
- 雪球效应,虽然我一个组件还是使用着同一个 mixin,但是一个 mixin 会被多个组件使用,可能会存在需求使得 mixin 修改原本的函数或者新增更多的函数,这样可能就会产生一个维护成本。
HOC 解决了这些问题,并且它们达成的效果也是一致的,同时也更加的政治正确(毕竟更加函数式了)。
八、React 中的高阶组件运用了什么设计模式?
使用了装饰模式,高阶组件的运用:
javascript
function withWindowWidth(BaseComponent) {
class DerivedClass extends React.Component {
state = {
windowWidth: window.innerWidth,
}
onResize = () => {
this.setState({
windowWidth: window.innerWidth,
})
}
componentDidMount() {
window.addEventListener('resize', this.onResize)
}
componentWillUnmount() {
window.removeEventListener('resize', this.onResize);
}
render() {
return <BaseComponent {...this.props} {...this.state}/>
}
}
return DerivedClass;
}
const MyComponent = (props) => {
return <div>Window width is: {props.windowWidth}</div>
};
export default withWindowWidth(MyComponent);
装饰模式的特点是不需要改变 被装饰对象 本身,而只是在外面套一个外壳接口。JavaScript 目前已经有了原生装饰器的提案,其用法如下:
javascript
@testable
class MyTestableClass {
}
九、React-Router怎么设置重定向?
使用<Redirect>组件实现路由的重定向:
html
<Switch>
<Redirect from='/users/:id' to='/users/profile/:id'/>
<Route path='/users/profile/:id' component={Profile}/>
</Switch>
当请求 /users/:id 被重定向去 '/users/profile/:id':
- 属性 from: string:需要匹配的将要被重定向路径。
- 属性 to: string:重定向的 URL 字符串
- 属性 to: object:重定向的 location 对象
- 属性 push: bool:若为真,重定向操作将会把新地址加入到访问历史记录里面,并且无法回退到前面的页面。
十、Redux 请求中间件如何处理并发
使用redux-Saga
redux-saga是一个管理redux应用异步操作的中间件,用于代替 redux-thunk 的。它通过创建 Sagas 将所有异步操作逻辑存放在一个地方进行集中处理,以此将react中的同步操作与异步操作区分开来,以便于后期的管理与维护。 redux-saga如何处理并发:
takeEvery
可以让多个 saga 任务并行被 fork 执行。
javascript
import {
fork,
take
} from "redux-saga/effects"
const takeEvery = (pattern, saga, ...args) => fork(function*() {
while (true) {
const action = yield take(pattern)
yield fork(saga, ...args.concat(action))
}
})
takeLatest
takeLatest 不允许多个 saga 任务并行地执行。一旦接收到新的发起的 action,它就会取消前面所有 fork 过的任务(如果这些任务还在执行的话)。
在处理 AJAX 请求的时候,如果只希望获取最后那个请求的响应, takeLatest 就会非常有用。
javascript
import {
cancel,
fork,
take
} from "redux-saga/effects"
const takeLatest = (pattern, saga, ...args) => fork(function*() {
let lastTask
while (true) {
const action = yield take(pattern)
if (lastTask) {
yield cancel(lastTask) // 如果任务已经结束,则 cancel 为空操作
}
lastTask = yield fork(saga, ...args.concat(action))
}
})
十一、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。
十一、React中的setState和replaceState的区别是什么?
(1)setState()
setState()用于设置状态对象,其语法如下:
javascript
setState(object nextState[, function callback])
- nextState,将要设置的新状态,该状态会和当前的state合并。
- callback,可选参数,回调函数。该函数会在setState设置成功,且组件重新渲染后调用。
合并nextState和当前state,并重新渲染组件。setState是React事件处理函数中和请求回调函数中触发UI更新的主要方法。
(2)replaceState()
replaceState()方法与setState()类似,但是方法只会保留nextState中状态,原state不在nextState中的状态都会被删除。其语法如下:
javascript
replaceState(object nextState[, function callback])
- nextState,将要设置的新状态,该状态会替换当前的state。
- callback,可选参数,回调函数。该函数会在replaceState设置成功,且组件重新渲染后调用。
**总结:**setState 是修改其中的部分状态,相当于 Object.assign,只是覆盖,不会减少原来的状态。而replaceState 是完全替换原来的状态,相当于赋值,将原来的 state 替换为另一个对象,如果新状态属性减少,那么 state 中就没有这个状态了。