为什么甚至在我们的代码并没有使用 React 的情况下,也需要在文件顶部 import React from 'react’
因为JSX语法调用了React.createElement
React 中 keys 的作用是什么?
Keys是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识
在开发过程中,我们需要保证某个元素的 key 在其同级元素中具有唯一性。在 React Diff 算法中React 会借助元素的 Key 值来判断该元素是新近创建的还是被移动而来的元素,从而减少不必要的元素重渲染。此外,React 还需要借助 Key 值来判断元素与本地状态的关联关系,因此我们绝不可忽视转换函数中 Key 的重要性
react中的函数组件与类组件
函数组件
function Welcome(props){
return <h1>Hello, {props.name}</h1>;
}
类组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
区别
- 类组件有state
- 类组件有生命周期函数
总结
- 函数组件写法比较简单,对于不需要state和生命周期函数调用的组件可使用函数组件。React未来也会对函数组件优化,提高其渲染性能。
- 对比较复杂的组件还是要使用类组件
children 属性是什么?
Children 是一个属性(this.props.chldren),它允许你将组件作为数据传递给其他组件,就像你使用的任何其他组件一样。在组件的开始和结束标记之间放置的组件树将作为children属性传递给该组件。
什么是无状态组件?
如果行为独立于其状态,则它可以是无状态组件。你可以使用函数或类来创建无状态组件。但除非你需要在组件中使用生命周期钩子,否则你应该选择函数组件。无状态组件有很多好处: 它们易于编写,理解和测试,速度更快,而且你可以完全避免使用this关键字。
什么是有状态组件?
如果组件的行为依赖于组件的state,那么它可以被称为有状态组件。这些有状态组件总是类组件,并且具有在constructor中初始化的状态。
什么是受控组件
在 HTML 中,类似 , 和 这样的表单元素会维护自身的状态,并基于用户的输入来更新。当用户提交表单时,前面提到的元素的值将随表单一起被发送。但在 React 中会有些不同,包含表单元素的组件将会在 state 中追踪输入的值,并且每次调用回调函数时,如 onChange 会更新 state,重新渲染组件。一个输入表单元素,它的值通过 React 的这种方式来控制,这样的元素就被称为"受控元素"。
什么是非受控组件?
非受控组件是在内部存储其自身状态的组件,当需要时,可以使用 ref 查询 DOM 并查找其当前值。这有点像传统的 HTML。
JSX语法的优点
- Jsx执行更快,因为在编译为JavaScript代码后进行了优化
- 使用jsx编写模板更加快速简单
- 它是类型安全的,在编译过程中就能发现错误
怎么阻止组件渲染?
在render方法中返回null
传入 setState 函数的第二个参数的作用是什么?
因为setState是一个异步的过程,所以说执行完setState之后不能立刻更改state里面的值。如果需要对state数据更改监听,setState提供第二个参数,就是用来监听state里面数据的更改,当数据更改完成,调用回调函数。我们可以用该函数来监听渲染是否完成。
this.setState(
{ username: 'tylermcginnis33' },
() => console.log('setState has finished and the component has re-rendered.')
)
React生命周期
- componentWillMount: 在组件render()前执行,用于根组件中的应用程序级别配置。应该避免在该方法中引入任何的副作用或订阅。
- componentDidMount: 首次渲染后调用,所有得 Ajax 请求、DOM 或状态更新、设置事件监听器都应该在此处发生。
- componentWillReceiveProps: 在组件接收到新属性前调用,若你需要更新状态响应属性改变(例如,重置它),你可能需对比this.props和nextProps并在该方法中使用this.setState()处理状态改变。
- shouldComponentUpdate: 确定组件是否应该更新。 默认情况下,它返回true。 如果你确定在更新状态或属性后不需要渲染组件,则可以返回false值。 它是一个提高性能的好地方,因为它允许你在组件接收新属性时阻止重新渲染。
- componentWillUpdate: 当shouldComponentUpdate返回true后重新渲染组件之前执行,注意你不能在这调用this.setState()
- componentDidUpdate: 它主要用于更新 DOM 以响应 prop 或 state 更改。 如果shouldComponentUpdate()返回false,则不会触发。
- componentWillUnmount: 当一个组件被从 DOM 中移除时,该方法被调用,取消网络请求或者移除与该组件相关的事件监听程序等应该在这里进行。
(在构造函数中)调用 super(props) 的目的是什么
在 super() 被调用之前,子类是不能使用 this 的,在 ES2015 中,子类必须在 constructor 中调用 super()。传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props。
当你调用setState的时候,发生了什么事?
当调用 setState 时,React会做的第一件事情是将传递给 setState 的对象合并到组件的当前状态。这将启动一个称为和解(reconciliation)的过程。和解(reconciliation)的最终目标是以最有效的方式,根据这个新的状态来更新UI。 为此,React将构建一个新的 React 元素树(您可以将其视为 UI 的对象表示)。
一旦有了这个树,为了弄清 UI 如何响应新的状态而改变,React 会将这个新树与上一个元素树相比较( diff )。
通过这样做, React 将会知道发生的确切变化,并且通过了解发生什么变化,只需在绝对必要的情况下进行更新即可最小化 UI 的占用空间。
React 中 refs 的作用是什么
- Refs 是 React 提供给我们的安全访问 DOM元素或者某个组件实例的句柄
- 可以为元素添加ref属性然后在回调函数中接受该元素在 DOM 树中的句柄,该值会作为回调函数的第一个参数返回
你什么时候需要使用 refs?
- 管理聚焦、文本选择或媒体播放。
- 触发命令式动画。
- 与第三方 DOM 库集成。
在生命周期中的哪一步你应该发起 AJAX 请求
我们应当将AJAX 请求放到 componentDidMount 函数中执行,主要原因有下
- React 下一代调和算法 Fiber 会通过开始或停止渲染的方式优化应用性能,其会影响到 componentWillMount 的触发次数。对于 componentWillMount 这个生命周期函数的调用次数会变得不确定,React 可能会多次频繁调用 componentWillMount。如果我们将 AJAX 请求放到 componentWillMount 函数中,那么显而易见其会被触发多次,自然也就不是好的选择。
- 如果我们将AJAX 请求放置在生命周期的其他函数中,我们并不能保证请求仅在组件挂载完毕后才会要求响应。如果我们的数据请求在组件挂载之前就完成,并且调用了setState函数将数据添加到组件状态中,对于未挂载的组件则会报错。而在 componentDidMount 函数中进行 AJAX 请求则能有效避免这个问题
shouldComponentUpdate 的作用
shouldComponentUpdate 允许我们手动地判断是否要进行组件更新,根据组件的应用场景设置函数的合理返回值能够帮我们避免不必要的更新
Real DOM 和 Virtual DOM 有什么区别?
以下是Real DOM和Virtual DOM之间的主要区别:
Real DOM | Virtual DOM |
---|---|
更新速度慢 | 更新速度快 |
DOM 操作非常昂贵 | DOM 操作非常简单 |
可以直接更新 HTML | 你不能直接更新 HTML |
造成太多内存浪费 | 更少的内存消耗 |
如果元素更新了,创建新的 DOM 节点 | 如果元素更新,则更新 JSX 元素 |
Virtual DOM 如何工作?
-
每当任何底层数据发生更改时,整个 UI 都将以 Virtual DOM 的形式重新渲染。
-
然后计算先前 Virtual DOM 对象和新的 Virtual DOM 对象之间的差异。
-
一旦计算完成,真实的 DOM 将只更新实际更改的内容。
React 的工作原理
React 会创建一个虚拟 DOM(virtual DOM)。当一个组件中的状态改变时,React 首先会通过 “diffing” 算法来标记虚拟 DOM 中的改变,第二步是调节(reconciliation),会用 diff 的结果来更新 DOM
React diff原理
把树形结构按照层级分解,只比较同级元素。
给列表结构的每个单元添加唯一的 key 属性,方便比较。
React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)
合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.
选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。
了解redux么?说一下redux
redux 是一个应用数据流框架,主要是解决了组件间状态共享的问题,原理是集中式管理,主要有三个核心方法,action,store,reducer,工作流程是 view 调用 store 的 dispatch 接收 action 传入 store,reducer 进行 state 操作,view 通过 store 提供的 getState 获取最新的数据,flux 也是用来进行数据操作的,有四个组成部分 action,dispatch,view,store,工作流程是 view 发出一个 action,派发器接收 action,让 store 进行数据更新,更新完成以后 store 发出 change,view 接受 change 更新视图。Redux 和 Flux 很像。主要区别在于 Flux 有多个可以改变应用状态的 store,在 Flux 中 dispatcher 被用来传递数据到注册的回调事件,但是在 redux 中只能定义一个可更新状态的 store,redux 把 store 和 Dispatcher 合并,结构更加简单清晰
新增 state,对状态的管理更加明确,通过 redux,流程更加规范了,减少手动编码量,提高了编码效率,同时缺点时当数据更新时有时候组件不需要,但是也要重新绘制,有些影响效率。一般情况下,我们在构建多交互,多数据流的复杂项目应用时才会使用它们
简述一下flux思想
Flux 的最大特点,就是数据的"单向流动"。
- 用户访问 View
- View 发出用户的 Action
- Dispatcher 收到 Action,要求 Store 进行相应的更新
- Store 更新后,发出一个"change"事件
- View 收到"change"事件后,更新页面
react高阶组件(HOC)
HOC就是一个函数,且该函数接受一个组件作为参数,并返回一个新组件。
import React, { Component } from 'react'
const withStorage = WrappedComponent => {
return class extends Component{
componentWillMount() {
let data = localStorage.getItem('data')
this.setState({ data })
}
render() {
return <WrappedComponent data={this.state.data} {...this.props} />
}
}
}
export default withStorage
// 直接调用即可
import React, { Component } from 'react'
import withStorage from '@/utils/withStorage'
class Page1 extends Component{
render() {
return <h2>{this.props.data}</h2>
}
}
export default withStorage(Page1)
高阶组件属于函数式编程(functional programming)思想,对于被包裹的组件时不会感知到高阶组件的存在,而高阶组件返回的组件会在原来的组件之上具有功能增强的效果。而Mixin这种混入的模式,会给组件不断增加新的方法和属性,组件本身不仅可以感知,甚至需要做相关的处理(例如命名冲突、状态维护),一旦混入的模块变多时,整个组件就变的难以维护,也就是为什么如此多的React库都采用高阶组件的方式进行开发。
redux的缺点
- 一个组件所需要的数据,必须由父组件传过来,而不能像flux中直接从store取。
- 当一个组件相关数据更新时,即使父组件不需要用到这个组件,父组件还是会重新render,可能会有效率影响,或者需要写复杂的shouldComponentUpdate进行判断。