- React.Component
- 组件的生命周期
- 常见生命周期方法介绍
- React.PureComponent
- diff算法
- React性能优化
- React严格模式
- 组件之间传值>Context
- Hook 规则
- 自定义 Hook
- 使用Hook
React.Component
React的组件可以定义为class或函数的形式。class组件目前提供了更多的功能。如需定义class组件,需要继承React.Component: 在React.Component的子类中,有个必须定义的render()函数,其他方法均为可选
class Welcome extends React.Component{
render(){
return (
<></>
)
}
}
组件的生命周期
常见的生命周期方法:
(1)挂载:当组件实例被创建并插入DOM中时,其生命周期调用顺序如下:
constructor()
render()
componentDidMount()
(2)更新:当组件的props或state发生变化时会触发更新。组件更新的生命周期调用顺序如下:
shouldComponentUpdate()
render()
componentDIdUpdate()
(3)卸载:当组件从DOM中移除时会调用如下方法:
componentWillUnMount()
常见生命周期方法介绍
(1)render()
render()方法是class组件中唯一必须实现的方法。当render被调用时,它会检查
this.props和this.state的变化。
(2)constructor()
如果不初始化state或者不进行方法绑定,则不需要为React组件实现构造函数。
(3)componentDidMount()
componentDidMount() 会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。
(4)componentDidUpdate()
componentDidUpdate() 会在更新后会被立即调用。首次渲染不会执行此方法
(5)componentWillUnmount()
componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等
React.PureComponent
React.PureComponent 与 React.Component 很相似。两者的区别在于React.Component并未实现shouldComponentUpdate(),而React.PureComponent中以浅层对比prop和state的方式来实现了该函数。
如果赋予 React 组件相同的 props 和 state,render() 函数会渲染相同的内容,那么在某些情况下使用 React.PureComponent 可提高性能。
注意:React.PureComponent 中的 shouldComponentUpdate() 仅作对象的浅层比较。
如果对象中包含复杂的数据结构,则有可能因为无法检查深层的差别,产生错误的比对结果。
仅在你的 props 和 state 较为简单时,才使用 React.PureComponent,
或者在深层数据结构发生变化时调用 forceUpdate() 来确保组件被正确地更新。
此外,React.PureComponent 中的 shouldComponentUpdate() 将跳过所有子组件树的 prop 更新。因此,请确保所有子组件也都是“纯”的组件。
diff算法
(1)设计动力:
在某一时间节点调用React的render()方法,会创建一颗由React元素组成的树。
在下一次state或props更新时,相同的render()方法会返回一颗不同的树。
React需要基于这两棵树之间的差别来判断如何有效的更新UI以保证当前UI与最新的树保持同步。
(2)diffing算法
当对比两颗树时,React首先比较两颗树的根节点。不同类型的根节点元素会有不用的形态。
(3)对比不同类型的元素
当根节点为不同类型的元素时,React 会拆卸原有的树并且建立起新的树。
(4)对比同一类型的元素
当对比两个相同类型的React元素时,React会保留DOM节点,仅对比以及更新有改变的属性。
(5)对比同类型的组件元素
当一个组件更新时,组件实例保持不变,这样 state 在跨越不同的渲染时保持一致。
(6)对子节点进行递归
在默认条件下,当递归DOM节点的子元素时,React会同时遍历两个子元素的列表;当产生差异时,生成一个mutation
此时在子元素列表末尾新增元素时,更新开销比较小。
(7)Keys
为了解决以上问题,React 支持 key 属性。当子元素拥有 key 时,React 使用 key 来匹配原有树上的子元素以及最新树上的子元素。
React性能优化
(1)部署时使用生产版本
React默认包含了许多有用的警告信息。这些警告信息在开发过程中非常有帮助。然而这使得React变得更大且更慢,所以你需要确保部署时使用了生产版本。
(2)虚拟化长列表
如果你的应用渲染了长列表,我们推荐使用“虚拟滚动”技术。这项技术会在有限的时间内仅渲染有限的内容,并奇迹般地降低重新渲染组件消耗的时间,以及创建 DOM 节点的数量。
react-window 和 react-virtualized 是热门的虚拟滚动库。 它们提供了多种可复用的组件,用于展示列表、网格和表格数据。 如果你想要一些针对你的应用做定制优化,你也可以创建你自己的虚拟滚动组件,就像 Twitter 所做的。
(3)避免调停
即使 React 只更新改变了的 DOM 节点,重新渲染仍然花费了一些时间。在大部分情况下它并不是问题,不过如果它已经慢到让人注意了,你可以通过覆盖生命周期方法 shouldComponentUpdate 来进行提速。该方法会在重新渲染前被触发。其默认实现总是返回 true,让 React 执行更新:
如果你知道在什么情况下你的组件不需要更新,你可以在 shouldComponentUpdate 中返回 false 来跳过整个渲染过程。其包括该组件的 render 调用以及之后的操作。
在大部分情况下,你可以继承 React.PureComponent 以代替手写 shouldComponentUpdate()。它用当前与之前 props 和 state 的浅比较覆写了 shouldComponentUpdate() 的实现。
React严格模式
StrictMode 是一个用来突出显示应用程序中潜在问题的工具。与 Fragment 一样,StrictMode 不会渲染任何可见的 UI。它为其后代元素触发额外的检查和警告。
注意:严格模式检查仅在开发模式下运行;它们不会影响生产构建。 你可以为应用程序的任何部分启用严格模式。
StrictMode 目前有助于:
识别不安全的生命周期
关于使用过时字符串 ref API 的警告
关于使用废弃的 findDOMNode 方法的警告
检测意外的副作用
检测过时的 context API
未来的 React 版本将添加更多额外功能。
state
正确地使用 State:不要直接修改 State,而是应该使用 setState()
State 的更新可能是异步的:可以让 setState() 接收一个函数而不是一个对象。
State 的更新会被合并
数据是向下流动的,单向数据流
state和props区别
(1)props 是传递给组件的,而 state 是在组件内被组件自己管理的
(2)props是只读的,state可以使用setstate修改状态
组件之间传值>Context
Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
使用方法:
const MyContext = React.createContext(defaultValue);
<MyContext.Provider value={/* 某个值 */}>
const contextType = MyContext;
创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。
只有当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效。这有助于在不使用 Provider 包装组件的情况下对组件进行测试。
注意:将 undefined 传递给 Provider 的 value 时,消费组件的 defaultValue 不会生效。
Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。
Hook 规则
1.只在最顶层使用 Hook
不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们。
2.只在 React 函数中调用 Hook
不要在普通的 JavaScript 函数中调用 Hook。你可以:
(1)✅ 在 React 的函数组件中调用 Hook
(2)✅ 在自定义 Hook 中调用其他 Hook
自定义 Hook
自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook。
使用Hook
(1)State Hook
const [‘当前 state’, ‘更新 state 的函数’] = useState(‘初始 state’);
(2)Effect Hook
Effect Hook 可以让你在函数组件中执行副作用操作
可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
1.需要清除的 effect
在useEffect中写一个返回函数并且写对应清除代码,React 将会在执行清除操作时调用它.
2.通过跳过 Effect 进行性能优化
在某些情况下,每次渲染后都执行清理或者执行 effect 可能会导致性能问题。useEffect 的 Hook API 中。
如果某些特定值在两次重渲染之间没有发生变化,你可以通知 React 跳过对 effect 的调用,只要传递数组作为 useEffect 的第二个可选参数即可。
注意:如果你要使用此优化方式,请确保数组中包含了所有外部作用域中会随时间变化并且在 effect 中使用的变量,否则你的代码会引用到先前渲染中的旧变量。
如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数。这就告诉 React 你的 effect 不依赖于 props 或 state 中的任何值,
所以它永远都不需要重复执行。这并不属于特殊情况 —— 它依然遵循依赖数组的工作方式。
如果你传入了一个空数组([]),effect 内部的 props 和 state 就会一直拥有其初始值。
(3)useContext
const value = useContext(MyContext);
接收一个context对象(React.createContext的返回值)并返回该context的当前值。当前context值由上层组件中距离当前组件最近的
<MyContext.Provider> 的 value prop 决定。
当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value 值。
别忘记 useContext 的参数必须是 context 对象本身:
React特点
之前我看React文档,然后里面有搜索框,我搜索过React特点,写的是React的关键特点是:
你可以重新渲染所有内容,并且不会重新生成DOM或者重置state
还是说的
虚拟dom(速度快)、组件化(提高代码的可维护性)、单向数据流(由上至下,状态更可控)
React缺点
React本身只是视图层框架,因此如果是大型项目需要一套完整框架,还需要在引入路由和状态管理等(redux和react-router)
react虚拟dom实现原理
在浏览器端js实现一套dom API,基于react开发时,所有dom操作都通过虚拟dom进行。
数据变化时,会重新构建整个dom树,虚拟dom会比较两个dom树的区别,
保证最小化的dom操作,然后仅将变化的部分进行实际的浏览器dom更新。
React组件如何传值
父传子:父组件通过属性传递,子组件通过props获取
子传父:通过父组件给子组件传递的方法传递数据
大型项目:redux
跨组件传递:使用context React.createContext
React中keys的作用
主要是减少没必要的diff算法的对比,因为对一个组件或节点来说,只要节点或属性发生变化,该组件就会进行diff对比。而引入了key值,就可以在diff对比前先做校验判断是否需要进行diff对比,即使对比,也可以判断该组件或者节点是直接新增、删除或更新,从而提高diff算法效率。
调用了setState后发生了什么
它是异步的,并不总是立即更新组件。它会批量推迟更新。
构造函数中调用super(props)的目的
如果不初始化state或不进行方法绑定,则不需要为React组件实现构造函数。
在React组件挂在之前,会调用它的构造函数。
在为React.Component子类实现构造函数时,
应在其他语句之前调用super(props)。
否则,this.props在构造函数中可能会出现未定义的bug。
React怎么从虚拟dom中拿出真实dom?
1、在构造函数中给当前组件添加属性并赋值 React.createRef()
2、再在要获取的dom节点上添加ref={this.刚才添加的属性}
3、获取节点:this.刚才添加的属性.current =>dom节点
==========================divider==========================
hook中
1、声明变量并赋值useRef<HTMLInputElement and so on>(null)
2、再在要获取的dom节点上添加ref={刚才添加的变量}
3、获取节点:变量.current =>dom节点
react router3是否用过,react router4是否用过,3到4有什么变化
router3需要进行集中式管理,router4哪里需要在哪里配置就可以。