React知识点滴(持续更新中)
发布时间 :
阅读 :
immutable JS的使用
immutable.js是Facebook推出的持久性数据结构的库。其中immutable指的是数据一旦创建,就不能再被更改,任何修改或者添加操作都会返回一个新的immutable对象。通过这个库可以让我们更容易的处理缓存、回退、数据变化检测等问题。
1 2 3 4 5 6 7 8
| import { Map } from "immutable"; const map1 = Map({ a: { aa: 1}, b: 2, c: 3}); const map2 = map1.set('b', 50); map1 !== map2; map1.get('b'); map2.get('b'); map1.get('a') === map2.get('a');
|
修改了map1的属性,赋值给map2;但是他们并不是指向同一个存储空间。map1操作不会改变map2,而且map1与map2的’a’指向同一个存储空间。下面举例它的其他一些操作。
1 2 3 4 5 6 7 8
| import { fromJS, isImmutable } from "immutable"; const obj = fromJS({ a: 'test', b: [1, 2, 4] }); isImmutable(obj); obj.size(); const obj1 = obj.toJS();
|
ImmutableJS 最大的两个特性就是: immutable data structures(持久性数据结构)与 structural sharing(结构共享),持久性数据结构保证数据一旦创建就不能修改,使用旧数据创建新数据时,旧数据也不会改变,不会像原生 js 那样新数据的操作会影响旧数据。而结构共享是指没有改变的数据共用一个引用,这样既减少了深拷贝的性能消耗,也减少了内存。比如下图:

左边是旧值,右边是新值,我需要改变左边红色节点的值,生成的新值改变了红色节点到根节点路径之间的所有节点,也就是所有青色节点的值,旧值没有任何改变,其他使用它的地方并不会受影响,而超过一大半的蓝色节点还是和旧值共享的。在 ImmutableJS 内部,构造了一种特殊的数据结构,把原生的值结合一系列的私有属性,创建成 ImmutableJS 类型,每次改变值,先会通过私有属性的辅助检测,然后改变对应的需要改变的私有属性和真实值,最后生成一个新的值,中间会有很多的优化,所以性能会很高。
在react中,setState是异步还是同步?
样例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| constructor(props) { super(props); this.state = { data: 'data' } }
componentDidMount() { this.setState({ data: 'did mount state' })
console.log("did mount state ", this.state.data);
setTimeout(() => { this.setState({ data: 'setTimeout' })
console.log("setTimeout ", this.state.data); }) }
|
第一额结果输出为data,而第二个会输出setTimeout。也就是说第一个setState是异步,第二个setState又成了同步。
先说下结论吧:
只要你进入了 react 的调度流程,那就是异步的。只要你没有进入 react 的调度流程,那就是同步的。什么东西不会进入 react 的调度流程? setTimeout setInterval ,直接在 DOM 上绑定原生事件等。这些都不会走 React 的调度流程,你在这种情况下调用 setState ,那这次 setState 就是同步的。 否则就是异步的。
而 setState 同步执行的情况下, DOM 也会被同步更新,也就意味着如果你多次 setState ,会导致多次更新,这是毫无意义并且浪费性能的。详细解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import React,{ Component } from "react"; class Count extends Component{ constructor(props){ super(props); this.state = { count:0 } }
render(){ return ( <> <p>count:{this.state.count}</p> <button onClick={this.btnAction}>增加</button> </> ) } btnAction = ()=>{ setTimeout(()=>{ this.setState({ count: this.state.count + 1 }); console.log(this.state.count); }) } }
export default Count;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import React,{ Component } from "react"; class Count extends Component{ constructor(props){ super(props); this.state = { count:0 } }
render(){ return ( <> <p>count:{this.state.count}</p> <button id="btn">绑定点击事件</button> </> ) } componentDidMount(){ document.querySelector('#btn').addEventListener('click',()=>{ this.setState({ count: this.state.count + 1 }); console.log(this.state.count); }); } }
export default Count;
|
React Hooks的使用
逻辑与UI分离 React官方推荐在开发中将逻辑部分与视图部分节藕,指责清晰
函数组件拥有State 在函数组件中,如果要实现类似的拥有state的状态,必须要将组件转为class
逻辑组件复用 社区一直致力于逻辑层面组件复用,像render props/HOC,但是他们有对应的问题。Hooks目前是比较理想的方案
这里举个例子,比如要实现一个Avatar头部图标。那么如果使用render props:
1 2 3 4 5 6 7 8
| export default function App() { return ( <div className="App"> <Avatar name="头像"> {name=> <User name={name} />} </Avatar> ); }
|
使用HOC:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import React, { Component } from 'react';
class Avatar extends Component { render() { return <div>{this.props.name}</div> } }
function HOCAvatar(Component) { return () => <Component name="头像"/> }
export default HOCAvatar(Avatar)
|
那么看下如果使用Hooks(代码量更少):
1 2 3 4 5 6
| import React, { useState } from "react";
export function HooksAvatar() { const [name, setName] = useState("头像"); return <>{name}</>; }
|
下面展示如何用hooks实现一个倒数定时器:
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 miaozixiong@gmail.com