如果你并非在做大型而复杂的应用, 你不需要过早地进行性能优化, 还是先把应用做出来吧
react性能优化
class组件优化
1.shouldComponentUpdate
比较组件的props和state是否真的发生变化,如果发生变化则返回true,否则返回false。引用官网的案例。
class CounterButton extends React.Component {
constructor(props) {
super(props);
this.state = {count: 1};
}
shouldComponentUpdate(nextProps, nextState) {
if (this.props.color !== nextProps.color) {
return true;
}
if (this.state.count !== nextState.count) {
return true;
}
return false;
}
render() {
return (
<button
color={this.props.color}
onClick={() => this.setState(state => ({count: state.count + 1}))}>
Count: {this.state.count}
</button>
);
}
}
2.PureComponent (PureRender是浅比较的,因为深比较的场景是相当昂贵的。所以不要直接为props设置对象或者数组、不要将方法直接绑定在元素上,因为其实函数也是对象)
handleClick() {
this.setState(prevState => ({
words: [...prevState.words, 'marklar'],
}));
};
function updateColorMap(colormap) {
return {...colormap, right: 'blue'};
}
3.Immutable(通过Immutable创建的Immutable Data一旦被创建,就不能再更改。对Immutable对象进行修改、添加或删除操作,都会返回一个新的Immutable对象。
immutable 内部使用了 Trie 数据结构来存储,只要两个对象的 hashCode 相等,值就是一样的。这样的算法避免了深度遍历比较,性能非常好。)
const SomeRecord = Immutable.Record({ foo: null });
const x = new SomeRecord({ foo: 'bar' });
const y = x.set('foo', 'baz');
x === y; // false
4.hooks
5.多个react组件性能优化,key的优化;
key属性在组件类之外提供了另一种方式的组件标识。通过key标识,在组件发生增删改、排序等操作时,可以根据key值的位置直接调整DOM顺序,告诉React 避免不必要的渲染而避免性能的浪费。
例,对于一个基于排序的组件渲染:
var items = sortBy(this.state.sortingAlgorithm, this.props.items);
return items.map(function(item){
return <img src={item.src} />
});
当顺序发生改变时,React 会对元素进行diff操作,并改img的src属性。显示,这样的操作效率是非常低的。这时,我们可以为组件添加一个key属性以唯一的标识组件:
return <img src={item.src} key={item.id} />
增加key后,React就不是diff,而是直接使用insertBefore操作移动组件位置,而这个操作是移动DOM节点最高效的办法。
6.bind函数
绑定this的方式:一般有下面3种方式:
1、constructor绑定
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this); //构造函数中绑定
}
//然后可以
<p onClick={this.handleClick}>
2、使用时绑定
<p onClick={this.handleClick.bind(this)}>
3、使用箭头函数
<Test click={() => { this.handleClick() }}/>
以上三种方法,第一种最优。
因为第一种构造函数只在组件初始化的时候执行一次,
第二种组件每次render都会执行
第三种在每一次render时候都会生成新的箭头函数。例:Test组件的click属性是个箭头函数,组件重新渲染的时候Test组件就会因为这个新生成的箭头函数而进行更新,从而产生Test组件的不必要渲染。
7.不要滥用props
props尽量只传需要的数据,避免多余的更新,尽量避免使用{…props}
8.不要用{{}}方式直接定义object,而是用一个变量进行缓存。
举个例子:
当我们给组件Foo给名为style的prop赋值;
<Foo style={{ color:“red” }}
使用这种方法,每一次渲染都会被认为是一个style这个prop发生了变化,因为每一次都会产生一个对象给style。
const fooStyle = { color: “red” }; //取保这个初始化只执行一次,不要放在render中,可以放在构造函数中
这个问题是我们在平时的编码中可以避免的。
8.react性能检测工具
hooks
- useMemo 优化
每个函数体当中生成的对象都会有新的引用, useMemo 可以保留一致的引用.
const myObject = useMemo(() => ({ key: "value" }), [])
- React.memo 优化
判断参数是否改变, 如果没有改变, 就直接复用已有的组件, 不重新生成
//React.memo 有第二个参数, 用于自定义判断的规则:
const MyComponent = React.memo(function MyComponent(props) {
/* only rerenders if props change */
});
- useCallback 优化
let Inner: FC<{
onClick: () => void
}> = React.memo((props) => {
return <div>
<span>inner</span>
</div>;
});
// onClick函数也是一种引用,如果是箭头函数每次都会重新生成新的对象
let Outer: FC<{}> = React.memo((props) => {
const [counter, setCounter] = useState(0);
const onClick = useCallback(()=>{
setCounter(prevState => ++prevState)
},[]);
return <div>
<span>outer: {counter}</span>
<Inner onClick={onClick} />
</div>;
});
- useRef 优化
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}