共计 8129 个字符,预计需要花费 21 分钟才能阅读完成。
解释 React 中 render() 的目标。
每个 React 组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的示意。如果须要渲染多个 HTML 元素,则必须将它们组合在一个关闭标记内,例如 <form>
、<group>
、<div>
等。此函数必须放弃污浊,即必须每次调用时都返回雷同的后果。
constructor
答案是:在 constructor 函数外面,须要用到 props 的值的时候,就须要调用 super(props)
- class 语法糖默认会帮你定义一个 constructor,所以当你不须要应用 constructor 的时候,是能够不必本人定义的
- 当你本人定义一个 constructor 的时候,就肯定要写 super(),否则拿不到 this
- 当你在 constructor 外面想要应用 props 的值,就须要传入 props 这个参数给 super,调用 super(props),否则只须要写 super()
react 的渲染过程中,兄弟节点之间是怎么解决的?也就是 key 值不一样的时候
通常咱们输入节点的时候都是 map 一个数组而后返回一个
ReactNode
,为了不便react
外部进行优化,咱们必须给每一个reactNode
增加key
,这个key prop
在设计值处不是给开发者用的,而是给 react 用的,大略的作用就是给每一个reactNode
增加一个身份标识,不便 react 进行辨认,在重渲染过程中,如果 key 一样,若组件属性有所变动,则react
只更新组件对应的属性;没有变动则不更新,如果 key 不一样,则 react 先销毁该组件,而后从新创立该组件
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 中绑定事件
何为受控组件(controlled component)
在 HTML 中,相似 <input>
, <textarea>
和 <select>
这样的表单元素会保护本身的状态,并基于用户的输出来更新。当用户提交表单时,后面提到的元素的值将随表单一起被发送。但在 React 中会有些不同,蕴含表单元素的组件将会在 state 中追踪输出的值,并且每次调用回调函数时,如 onChange
会更新 state,从新渲染组件。一个输出表单元素,它的值通过 React 的这种形式来管制,这样的元素就被称为 ” 受控元素 ”。
React.Children.map 和 js 的 map 有什么区别?
JavaScript 中的 map 不会对为 null 或者 undefined 的数据进行解决,而 React.Children.map 中的 map 能够解决 React.Children 为 null 或者 undefined 的状况。
参考 前端进阶面试题具体解答
在 React 中组件的 this.state 和 setState 有什么区别?
this.state 通常是用来初始化 state 的,this.setState 是用来批改 state 值的。如果初始化了 state 之后再应用 this.state,之前的 state 会被笼罩掉,如果应用 this.setState,只会替换掉相应的 state 值。所以,如果想要批改 state 的值,就须要应用 setState,而不能间接批改 state,间接批改 state 之后页面是不会更新的。
什么是受控组件和非受控组件
- 受状态管制的组件,必须要有 onChange 办法,否则不能应用 受控组件能够赋予默认值(官网举荐应用 受控组件)实现双向数据绑定
class Input extends Component{constructor(){super();
this.state = {val:'100'}
}
handleChange = (e) =>{ // e 是事件源
let val = e.target.value;
this.setState({val});
};
render(){
return (<div>
<input type="text" value={this.state.val} onChange={this.handleChange}/>
{this.state.val}
</div>)
}
}
- 非受控也就意味着我能够不须要设置它的 state 属性,而通过 ref 来操作实在的 DOM
class Sum extends Component{constructor(){super();
this.state = {result:''}
}
// 通过 ref 设置的属性 能够通过 this.refs 获取到对应的 dom 元素
handleChange = () =>{
let result = this.refs.a.value + this.b.value;
this.setState({result});
};
render(){
return (<div onChange={this.handleChange}>
<input type="number" ref="a"/>
{/* x 代表的实在的 dom, 把元素挂载在了以后实例上 */}
<input type="number" ref={(x)=>{this.b = x;}}/>
{this.state.result}
</div>
)
}
}
对 componentWillReceiveProps 的了解
该办法当 props
发生变化时执行,初始化 render
时不执行,在这个回调函数外面,你能够依据属性的变动,通过调用 this.setState()
来更新你的组件状态,旧的属性还是能够通过 this.props
来获取, 这里调用更新状态是平安的,并不会触发额定的 render
调用。
应用益处: 在这个生命周期中,能够在子组件的 render 函数执行前获取新的 props,从而更新子组件本人的 state。能够将数据申请放在这里进行执行,须要传的参数则从 componentWillReceiveProps(nextProps)中获取。而不用将所有的申请都放在父组件中。于是该申请只会在该组件渲染时才会收回,从而加重申请累赘。
componentWillReceiveProps 在初始化 render 的时候不会执行,它会在 Component 承受到新的状态 (Props) 时被触发,个别用于父组件状态更新时子组件的从新渲染。
redux 是如何更新值得
用户发动操作之后,dispatch 发送 action,依据 type,触发对于的 reducer,reducer 就是一个纯函数,接管旧的 state 和 action,返回新的 state。通过 subscribe(listener)监听器,派发更新。
在 React 中遍历的办法有哪些?
(1)遍历数组:map && forEach
import React from 'react';
class App extends React.Component {render() {let arr = ['a', 'b', 'c', 'd'];
return (
<ul>
{arr.map((item, index) => {return <li key={index}>{item}</li>
})
}
</ul>
)
}
}
class App extends React.Component {render() {let arr = ['a', 'b', 'c', 'd'];
return (
<ul>
{arr.forEach((item, index) => {return <li key={index}>{item}</li>
})
}
</ul>
)
}
}
(2)遍历对象:map && for in
class App extends React.Component {render() {
let obj = {
a: 1,
b: 2,
c: 3
}
return (
<ul>
{(() => {let domArr = [];
for(const key in obj) {if(obj.hasOwnProperty(key)) {const value = obj[key]
domArr.push(<li key={key}>{value}</li>)
}
}
return domArr;
})()}
</ul>
)
}
}
// Object.entries() 把对象转换成数组
class App extends React.Component {render() {
let obj = {
a: 1,
b: 2,
c: 3
}
return (
<ul>
{Object.entries(obj).map(([key, value], index) => {// item 是一个数组,把 item 解构,写法是[key, value]
return <li key={key}>{value}</li>
})
}
</ul>
)
}
}
什么是状态晋升
应用 react 常常会遇到几个组件须要共用状态数据的状况。这种状况下,咱们最好将这部分共享的状态晋升至他们最近的父组件当中进行治理。咱们来看一下具体如何操作吧。
import React from 'react'
class Child_1 extends React.Component{constructor(props){super(props)
}
render(){
return (
<div>
<h1>{this.props.value+2}</h1>
</div>
)
}
}
class Child_2 extends React.Component{constructor(props){super(props)
}
render(){
return (
<div>
<h1>{this.props.value+1}</h1>
</div>
)
}
}
class Three extends React.Component {constructor(props){super(props)
this.state = {txt:"牛逼"}
this.handleChange = this.handleChange.bind(this)
}
handleChange(e){
this.setState({txt:e.target.value})
}
render(){
return (
<div>
<input type="text" value={this.state.txt} onChange={this.handleChange}/>
<p>{this.state.txt}</p>
<Child_1 value={this.state.txt}/>
<Child_2 value={this.state.txt}/>
</div>
)
}
}
export default Three
展现组件 (Presentational component) 和容器组件 (Container component) 之间有何不同
展现组件关怀组件看起来是什么。展现专门通过 props 承受数据和回调,并且简直不会有本身的状态,但当展现组件领有本身的状态时,通常也只关怀 UI 状态而不是数据的状态。
容器组件则更关怀组件是如何运作的。容器组件会为展现组件或者其它容器组件提供数据和行为 (behavior),它们会调用 Flux actions
,并将其作为回调提供给展现组件。容器组件常常是有状态的,因为它们是(其它组件的) 数据源。
React Hook 的应用限度有哪些?
React Hooks 的限度次要有两条:
- 不要在循环、条件或嵌套函数中调用 Hook;
- 在 React 的函数组件中调用 Hook。
那为什么会有这样的限度呢?Hooks 的设计初衷是为了改良 React 组件的开发模式。在旧有的开发模式下遇到了三个问题。
- 组件之间难以复用状态逻辑。过来常见的解决方案是高阶组件、render props 及状态治理框架。
- 简单的组件变得难以了解。生命周期函数与业务逻辑耦合太深,导致关联局部难以拆分。
- 人和机器都很容易混同类。常见的有 this 的问题,但在 React 团队中还有类难以优化的问题,心愿在编译优化层面做出一些改良。
这三个问题在肯定水平上妨碍了 React 的后续倒退,所以为了解决这三个问题,Hooks 基于函数组件 开始设计。然而第三个问题决定了 Hooks 只反对函数组件。
那为什么不要在循环、条件或嵌套函数中调用 Hook 呢?因为 Hooks 的设计是基于数组实现。在调用时按程序退出数组中,如果应用循环、条件或嵌套函数很有可能导致数组取值错位,执行谬误的 Hook。当然,本质上 React 的源码里不是数组,是链表。
这些限度会在编码上造成肯定水平的心智累赘,老手可能会写错,为了防止这样的状况,能够引入 ESLint 的 Hooks 查看插件进行预防。
应用 React 有何长处
- 只需查看
render
函数就会很容易晓得一个组件是如何被渲染的 - JSX 的引入,使得组件的代码更加可读,也更容易看懂组件的布局,或者组件之间是如何相互援用的
- 反对服务端渲染,这能够改良 SEO 和性能
- 易于测试
- React 只关注 View 层,所以能够和其它任何框架 (如 Backbone.js, Angular.js) 一起应用
React key 是干嘛用的 为什么要加?key 次要是解决哪一类问题的
Keys 是 React 用于追踪哪些列表中元素被批改、被增加或者被移除的辅助标识。在开发过程中,咱们须要保障某个元素的 key 在其同级元素中具备唯一性。
在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是早先创立的还是被挪动而来的元素,从而缩小不必要的元素重渲染此外,React 还须要借助 Key 值来判断元素与本地状态的关联关系。
注意事项:
- key 值肯定要和具体的元素—一对应;
- 尽量不要用数组的 index 去作为 key;
- 不要在 render 的时候用随机数或者其余操作给元素加上不稳固的 key,这样造成的性能开销比不加 key 的状况下更蹩脚。
Component, Element, Instance 之间有什么区别和分割?
- 元素: 一个元素
element
是一个一般对象 (plain object),形容了对于一个 DOM 节点或者其余组件component
,你想让它在屏幕上出现成什么样子。元素element
能够在它的属性props
中蕴含其余元素 (译注: 用于造成元素树)。创立一个 React 元素element
老本很低。元素element
创立之后是不可变的。 - 组件: 一个组件
component
能够通过多种形式申明。能够是带有一个render()
办法的类,简略点也能够定义为一个函数。这两种状况下,它都把属性props
作为输出,把返回的一棵元素树作为输入。 - 实例: 一个实例
instance
是你在所写的组件类component class
中应用关键字this
所指向的货色(译注: 组件实例)。它用来存储本地状态和响应生命周期事件很有用。
函数式组件 (Functional component
) 基本没有实例 instance
。类组件(Class component
) 有实例instance
,然而永远也不须要间接创立一个组件的实例,因为 React 帮咱们做了这些。
同时援用这三个库 react.js、react-dom.js 和 babel.js 它们都有什么作用?
- react:蕴含 react 所必须的外围代码
- react-dom:react 渲染在不同平台所须要的外围代码
- babel:将 jsx 转换成 React 代码的工具
如何将两个或多个组件嵌入到一个组件中?
能够通过以下形式将组件嵌入到一个组件中:
class MyComponent extends React.Component{render(){
return(
<div>
<h1>Hello</h1>
<Header/>
</div>
);
}
}
class Header extends React.Component{render(){
return
<h1>Header Component</h1>
};
}
ReactDOM.render(<MyComponent/>, document.getElementById('content')
);
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。