前端面试题视频解说
constructor 为什么不先渲染?
由 ES6 的继承规定得悉,不论子类写不写 constructor,在 new 实例的过程都会给补上 constructor。
所以:constructor 钩子函数并不是不可短少的,子组件能够在一些状况略去。比方不本人的 state,从 props 中获取的状况
react 版本差别
react16.8 hooks
React 16 之后有三个生命周期被废除(但并未删除)
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
官网打算在 17 版本齐全删除这三个函数,只保留 UNSAVE_前缀的三个函数,目标是为了向下兼容,
react 16.4 新增
getSnapshotBeforeUpdate
getDerivedStateFromProps
对于废除的生命周期函数,官网会采纳逐渐迁徙的形式来实现版本的迁徙:
16.3:为不平安的生命周期引入别名,UNSAFE_componentWillMount、UNSAFE_componentWillReceiveProps 和 UNSAFE_componentWillUpdate。(旧的生命周期名称和新的别名都能够在此版本中应用。)
将来 16.x 版本:为 componentWillMount、componentWillReceiveProps 和 componentWillUpdate 启用废除告警。(旧的生命周期名称和新的别名都将在这个版本中工作,然而旧的名称在开发模式下会产生一个正告。)
17.0:删除 componentWillMount、componentWillReceiveProps 和 componentWillUpdate。(在此版本之后,只有新的“UNSAFE_”生命周期名称能够应用。)。
如何在 ReactJS 的 Props 上利用验证?
当应用程序在开发模式下运行时,React 将主动查看咱们在组件上设置的所有 props
,以确保它们具备正确的数据类型。对于不正确的类型,开发模式下会在控制台中生成正告音讯,而在生产模式中因为性能影响而禁用它。强制的 props
用 isRequired
定义的。
上面是一组预约义的 prop 类型:
- React.PropTypes.string
- React.PropTypes.number
- React.PropTypes.func
- React.PropTypes.node
-
React.PropTypes.bool
例如,咱们为用户组件定义了如下的propTypes
import PropTypes from "prop-types"; class User extends React.Component {render() { return ( <> <h1>Welcome, {this.props.name}</h1> <h2>Age, {this.props.age}</h2> </> ); } } User.propTypes = { name: PropTypes.string.isRequired, age: PropTypes.number.isRequired, };
setState 办法的第二个参数有什么用?应用它的目标是什么?
它是一个回调函数,当 setState 办法执行完结并从新渲染该组件时调用它。在工作中,更好的形式是应用 React 组件生命周期之——“存在期”的生命周期办法,而不是依赖这个回调函数。
export class App extends Component {constructor(props) {super(props);
this.state = {username: "雨夜清荷",};
}
render() {return <div> {this.state.username}</div>;
}
componentDidMount() {
this.setstate(
{username: "有课前端网",},
() => console.log("re-rendered success.")
);
}
}
跨级组件的通信形式?
父组件向子组件的子组件通信,向更深层子组件通信:
- 应用 props,利用两头组件层层传递, 然而如果父组件构造较深,那么两头每一层组件都要去传递 props,减少了复杂度,并且这些 props 并不是两头组件本人须要的。
- 应用 context,context 相当于一个大容器,能够把要通信的内容放在这个容器中,这样不论嵌套多深,都能够随便取用,对于逾越多层的全局数据能够应用 context 实现。
// context 形式实现跨级组件通信
// Context 设计目标是为了共享那些对于一个组件树而言是“全局”的数据
const BatteryContext = createContext();
// 子组件的子组件
class GrandChild extends Component {render(){
return (
<BatteryContext.Consumer>
{color => <h1 style={{"color":color}}> 我是红色的:{color}</h1>
} </BatteryContext.Consumer>
)
}
}
// 子组件
const Child = () =>{
return (<GrandChild/>)
}
// 父组件
class Parent extends Component {
state = {color:"red"}
render(){const {color} = this.state
return (<BatteryContext.Provider value={color}>
<Child></Child>
</BatteryContext.Provider>
)
}
}
复制代码
应用箭头函数 (arrow functions) 的长处是什么
- 作用域平安:在箭头函数之前,每一个新创建的函数都有定义本身的
this
值(在构造函数中是新对象;在严格模式下,函数调用中的this
是未定义的;如果函数被称为“对象办法”,则为根底对象等),但箭头函数不会,它会应用关闭执行上下文的this
值。 - 简略:箭头函数易于浏览和书写
- 清晰:当一切都是一个箭头函数,任何惯例函数都能够立刻用于定义作用域。开发者总是能够查找 next-higher 函数语句,以查看
this
的值
何为纯函数(pure function)
一个纯函数是一个不依赖于且不扭转其作用域之外的变量状态的函数,这也意味着一个纯函数对于同样的参数总是返回同样的后果。
怎么用 React.createElement 重写上面的代码
Question:
const element = (
<h1 className="greeting">
Hello, rdhub.cn!
</h1>
);
Answer:
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, rdhub.cn!'
);
React 性能优化在哪个生命周期?它优化的原理是什么?
react 的父级组件的 render 函数从新渲染会引起子组件的 render 办法的从新渲染。然而,有的时候子组件的承受父组件的数据没有变动。子组件 render 的执行会影响性能,这时就能够应用 shouldComponentUpdate 来解决这个问题。
应用办法如下:
shouldComponentUpdate(nexrProps) {if (this.props.num === nexrProps.num) {return false}
return true;
}
复制代码
shouldComponentUpdate 提供了两个参数 nextProps 和 nextState,示意下一次 props 和一次 state 的值,当函数返回 false 时候,render()办法不执行,组件也就不会渲染,返回 true 时,组件照常重渲染。此办法就是拿以后 props 中值和下一次 props 中的值进行比照,数据相等时,返回 false,反之返回 true。
须要留神,在进行新旧比照的时候,是 浅比照,也就是说如果比拟的数据时援用数据类型,只有数据的援用的地址没变,即便内容变了,也会被断定为 true。
面对这个问题,能够应用如下办法进行解决:
(1)应用 setState 扭转数据之前,先采纳 ES6 中 assgin 进行拷贝,然而 assgin 只深拷贝的数据的第一层,所以说不是最完满的解决办法:
const o2 = Object.assign({},this.state.obj)
o2.student.count = '00000';
this.setState({obj: o2,})
复制代码
(2)应用 JSON.parse(JSON.stringfy())进行深拷贝,然而遇到数据为 undefined 和函数时就会错。
const o2 = JSON.parse(JSON.stringify(this.state.obj))
o2.student.count = '00000';
this.setState({obj: o2,})
复制代码
何为 JSX
JSX 是 JavaScript 语法的一种语法扩大,并领有 JavaScript 的全副性能。JSX 生产 React “ 元素 ”,你能够将任何的 JavaScript 表达式封装在花括号里,而后将其嵌入到 JSX 中。在编译实现之后,JSX 表达式就变成了惯例的 JavaScript 对象,这意味着你能够在 if
语句和 for
循环外部应用 JSX,将它赋值给变量,承受它作为参数,并从函数中返回它。
constructor
答案是:在 constructor 函数外面,须要用到 props 的值的时候,就须要调用 super(props)
- class 语法糖默认会帮你定义一个 constructor,所以当你不须要应用 constructor 的时候,是能够不必本人定义的
- 当你本人定义一个 constructor 的时候,就肯定要写 super(),否则拿不到 this
- 当你在 constructor 外面想要应用 props 的值,就须要传入 props 这个参数给 super,调用 super(props),否则只须要写 super()
React-Router 怎么设置重定向?
应用 <Redirect>
组件实现路由的重定向:
<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 怎么实现属性传递,介绍下原理
react-redux 数据传输∶ view–>action–>reducer–>store–>view。看下点击事件的数据是如何通过 redux 传到 view 上:
- view 上的 AddClick 事件通过 mapDispatchToProps 把数据传到 action —> click:()=>dispatch(ADD)
- action 的 ADD 传到 reducer 上
- reducer 传到 store 上 const store = createStore(reducer);
- store 再通过 mapStateToProps 映射穿到 view 上 text:State.text
代码示例∶
import React from 'react';
import ReactDOM from 'react-dom';
import {createStore} from 'redux';
import {Provider, connect} from 'react-redux';
class App extends React.Component{render(){let { text, click, clickR} = this.props;
return(
<div>
<div> 数据: 已有人{text}</div>
<div onClick={click}> 加人 </div>
<div onClick={clickR}> 减人 </div>
</div>
)
}
}
const initialState = {text:5}
const reducer = function(state,action){switch(action.type){
case 'ADD':
return {text:state.text+1}
case 'REMOVE':
return {text:state.text-1}
default:
return initialState;
}
}
let ADD = {type:'ADD'}
let Remove = {type:'REMOVE'}
const store = createStore(reducer);
let mapStateToProps = function (state){
return{text:state.text}
}
let mapDispatchToProps = function(dispatch){
return{click:()=>dispatch(ADD),
clickR:()=>dispatch(Remove)
}
}
const App1 = connect(mapStateToProps,mapDispatchToProps)(App);
ReactDOM.render(<Provider store = {store}>
<App1></App1>
</Provider>,document.getElementById('root')
)
复制代码
React-Router 4 的 Switch 有什么用?
Switch 通常被用来包裹 Route,用于渲染与门路匹配的第一个子 <Route>
或 <Redirect>
,它外面不能放其余元素。
如果不加 <Switch>
:
import {Route} from 'react-router-dom'
<Route path="/" component={Home}></Route>
<Route path="/login" component={Login}></Route>
复制代码
Route 组件的 path 属性用于匹配门路,因为须要匹配 /
到 Home
,匹配 /login
到 Login
,所以须要两个 Route,然而不能这么写。这样写的话,当 URL 的 path 为“/login”时,<Route path="/" />
和<Route path="/login" />
都会被匹配,因而页面会展现 Home 和 Login 两个组件。这时就须要借助 <Switch>
来做到只显示一个匹配组件:
import {Switch, Route} from 'react-router-dom'
<Switch>
<Route path="/" component={Home}></Route>
<Route path="/login" component={Login}></Route>
</Switch>
复制代码
此时,再拜访“/login”门路时,却只显示了 Home 组件。这是就用到了 exact 属性,它的作用就是准确匹配门路,常常与<Switch>
联结应用。只有当 URL 和该 <Route>
的 path 属性完全一致的状况下能力匹配上:
import {Switch, Route} from 'react-router-dom'
<Switch>
<Route exact path="/" component={Home}></Route>
<Route exact path="/login" component={Login}></Route>
</Switch>
React 中的 setState 批量更新的过程是什么?
调用 setState
时,组件的 state
并不会立刻扭转,setState
只是把要批改的 state
放入一个队列,React
会优化真正的执行机会,并出于性能起因,会将 React
事件处理程序中的屡次React
事件处理程序中的屡次 setState
的状态批改合并成一次状态批改。最终更新只产生一次组件及其子组件的从新渲染,这对于大型应用程序中的性能晋升至关重要。
this.setState({count: this.state.count + 1 ===> 入队,[count+ 1 的工作]
});
this.setState({count: this.state.count + 1 ===> 入队,[count+ 1 的工作,count+ 1 的工作]
});
↓
合并 state,[count+ 1 的工作]
↓
执行 count+ 1 的工作
复制代码
须要留神的是,只有同步代码还在执行,“攒起来”这个动作就不会进行。(注:这里之所以屡次 +1 最终只有一次失效,是因为在同一个办法中屡次 setState 的合并动作不是单纯地将更新累加。比方这里对于雷同属性的设置,React 只会为其保留最初一次的更新)。
(在构造函数中)调用 super(props) 的目标是什么
在 super()
被调用之前,子类是不能应用 this
的,在 ES2015 中,子类必须在 constructor
中调用 super()
。传递 props
给 super()
的起因则是便于 (在子类中) 能在 constructor
拜访 this.props
。
何为 redux
Redux 的根本思维是整个利用的 state 放弃在一个繁多的 store 中。store 就是一个简略的 javascript 对象,而扭转利用 state 的惟一形式是在利用中触发 actions,而后为这些 actions 编写 reducers 来批改 state。整个 state 转化是在 reducers 中实现,并且不应该有任何副作用。
何为高阶组件(higher order component)
高阶组件是一个以组件为参数并返回一个新组件的函数。HOC 运行你重用代码、逻辑和疏导形象。最常见的可能是 Redux 的 connect
函数。除了简略分享工具库和简略的组合,HOC 最好的形式是共享 React 组件之间的行为。如果你发现你在不同的中央写了大量代码来做同一件事时,就应该思考将代码重构为可重用的 HOC。
练习
- 写一个反转其输出的 HOC
- 写一个从 API 提供数据给传入的组件的 HOC
- 写一个实现 shouldComponentUpdate 来防止 reconciliation 的 HOC
- 写一个通过
React.Children.toArray
对传入组件的子组件进行排序的 HOC