react 部分
为什么不能用数组下标来作为react组件中的key?
react 使用diff算法,使用key来做同级比对。如果使用数组下标作为key,有以下情况:在数组头部或中部插入或删除元素: 所有key对应的节点的值发生更改,进行重新渲染。造成性能损耗而如果使用数组中唯一值来作为key:不管是在何处插入或删除节点,其他key对应的节点的值未发生更改,只需插入或删除操作的数组节点。
react shouldComponentUpdate 函数的作用?
使用shouldComponentUpdate()以让React知道当前状态或属性的改变是否不影响组件的输出,默认返回ture,返回false时不会重写render,而且该方法并不会在初始化渲染或当使用forceUpdate()时被调用.
如果在组件树的根节点发生更新则所有子节点都会发生更新,这时对所有子节点使用shouldComponentUpdate来减少子节点的渲染,无疑会增加很多代码。我们可以选择使用PureComponent来处理。
React.PureComponent 和 React.Component
PureComponent 和 Component的区别是:Component需要手动实现 shouldComponentUpdate,而PureComponent通过浅对比默认实现了shouldComponentUpdate方法
浅比较
(shallowEqual),即react源码中的一个函数,然后根据下面的方法进行是不是PureComponent
的判断,帮我们做了本来应该我们在shouldComponentUpdate
中做的事情
if (this._compositeType === CompositeTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState);
}
注意: 浅比较只比较了第一层,复杂数据结构可能会导致更新问题
总结: PureComponent不仅会影响本身,而且会影响子组件,所以PureComponent最佳情况是展示组件
React.memo
React.memo为高阶组件。它与 React.PureComponent 非常相似,但它适用于函数组件,但不适用于 class 组件。如果你的函数组件在给定相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo 中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。
React.memo 依然是浅比较(默认)。在React.memo
中可以自定义其比较方法的实现。
function MyComponent(props) {
/* render using props */
}
function areEqual(prevProps, nextProps) {
/*
return true if passing nextProps to render would return
the same result as passing prevProps to render,
otherwise return false
*/
}
export default React.memo(MyComponent, areEqual);
和PureComponent的区别:
- memo为函数组件,PureComponent为类组件
- memo 默认和PureComponent为浅比较
- memo 如果相同props的情况下将跳过渲染直接服用最近一次渲染的效果
配合Immutable来实现比较
Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
因为使用Immutable 任何修改或添加删除操作都会返回新的Immutable 对象,所以只需简单比较即可,可参考如下代码
// 使用 immutable.js 后
let map1 = Immutable.Map({a:1, b:1, c:1});
let map2 = Immutable.Map({a:1, b:1, c:1});
map1 === map2; // false
// 为了直接比较对象的值,immutable.js 提供了 \`Immutable.is\` 来做『值比较』
Immutable.is(map1, map2); // true
流行的 Immutable 库有两个:
- immutable.js
- seamless-immutable
// 原来的写法
let foo = {a: {b: 1}};
let bar = foo;
bar.a.b = 2;
console.log(foo.a.b); // 打印 2
console.log(foo === bar); // 打印 true
// 使用 immutable.js 后
import Immutable from 'immutable';
foo = Immutable.fromJS({a: {b: 1}});
bar = foo.setIn(['a', 'b'], 2); // 使用 setIn 赋值
console.log(foo.getIn(['a', 'b'])); // 使用 getIn 取值,打印 1
console.log(foo === bar); // 打印 false
// 使用 seamless-immutable.js 后
import SImmutable from 'seamless-immutable';
foo = SImmutable({a: {b: 1}})
bar = foo.merge({a: { b: 2}}) // 使用 merge 赋值
console.log(foo.a.b); // 像原生 Object 一样取值,打印 1
console.log(foo === bar); // 打印 false
Immutable 优点:
1、Immutable 降低了 Mutable 带来的复杂度
2、节省内存(Immutable.js 使用了 Structure Sharing 会尽量复用内存。没有被引用的对象会被垃圾回收。)
import { Map} from 'immutable';
let a = Map({
select: 'users',
filter: Map({ name: 'Cam' })
})
let b = a.set('select', 'people');
a === b; // false
a.get('filter') === b.get('filter'); // true a 和 b 共享了没有变化的 \`filter\` 节点
3、拥抱函数式编程
Immutable 本身就是函数式编程中的概念,纯函数式编程比面向对象更适用于前端开发。因为只要输入一致,输出必然一致,这样开发的组件更易于调试和组装。
4、Undo/Redo,Copy/Paste&