Code Monkey home page Code Monkey logo

blog's People

Contributors

liekkas avatar

Watchers

 avatar

blog's Issues

react优化之key的妙用

在通过遍历数组来创建组件的时候react往往提示你要为组件设置一个唯一key值。很多情况下一般就直接用索引来当这个值了,方便又简单如:

this.state.cells.map(({name,x,y},index) =>
            <Cell name={name} key={index} x={x} y={y} onRemove={(t) => this.onRemove(t)}/>
          )

但这里有个问题,假如这个数组是动态可变的,你会发现简单的只设置key=index会带来不必要的重绘开支。现在来看看这种情况。

我们有两个组件,画布容器Spacer,独立组件Cell,容器中有添加按钮,每点一次就添加一个Cell,Cell就一个label用来区分,还有删除按钮来移除该Cell的简单组件。

这两个组件的代码如下:

Spacer组件:

import React, { PropTypes } from 'react';
import Cell from './Cell.jsx';
import _ from 'lodash';

class Spacer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      cells: [],
    };
  }

  addCell() {
    this.state.cells.push({
      name: _.uniqueId('label'),
      x: _.random(1000),
      y: _.random(800),
    });
    this.setState({cells: this.state.cells});
  }

  onRemove(name) {
    const index = _.findIndex(this.state.cells, 'name', name);
    const cells = this.state.cells.splice(index,1);
    this.setState({cells: this.state.cells});
  }

  render() {
    console.log('>>> Spacer:render', this.state.cells);
    return (
      <div style={{
        width: '100%',
        height: '100%',
        padding: '10px',
      }}>
        <button onClick={() => this.addCell()}>添加</button>
        {
          this.state.cells.map(({name,x,y},index) =>
            <Cell name={name} key={index} x={x} y={y} onRemove={(t) => this.onRemove(t)}/>
          )
        }
      </div>
    );
  }
}

Spacer.propTypes = {
  foo: PropTypes.string.isRequired,
};
Spacer.defaultProps = {
  foo: 'bar',
};

export default Spacer;

Cell组件:

import React, { PropTypes } from 'react';

class Cell extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'bar',
    };
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log('>>> Cell:shouldComponentUpdate',this.props.name,nextProps.name);
    return this.props.name !== nextProps.name ||
      this.props.x !== nextProps.x ||
      this.props.y !== nextProps.y;
  }

  componentDidUpdate(prevProps, prevState) {
    console.log('>>> Cell:componentDidUpdate');
  }

  render() {
    const { name, x, y, onRemove } = this.props;
    console.log('>>> Cell:render',name);
    return (
      <div style={{
        position: 'absolute',
        padding: '4px',
        width: '100px',
        height: '100px',
        border: '1px solid',
        left: x + 'px',
        top: y + 'px',
      }}>
        {name}
        <div style={{
          width: '100%',
          height: '20px',
          cursor: 'pointer',
          background: '#aabbcc',
        }} onClick={() => onRemove(name)}>
          删除
        </div>
      </div>
    );
  }
}

Cell.propTypes = {
  x: PropTypes.number.isRequired,
  y: PropTypes.number.isRequired,
  name: PropTypes.string.isRequired,
  onRemove: PropTypes.func.isRequired,
};
Cell.defaultProps = {
  name: 'bar',
};

export default Cell;

假如现在你添加了四个组件:c1,c2,c3,c4,打开控制台,因为Cell组件中我们在shouldComponentUpdate方法里加了判断只有组件名字或者坐标发生了变化才重绘,因此添加时c1,c2,c3,c4格子只重绘一次。

现在你从最末起删除c4,控制没有提示有组件重绘,符合咱们预期。留下c1,c2,c3。
你再从中间开始删除,你删除c2,那么你会发现c3重绘了一次?

为啥会发生这样的关联?删除c2跟c3有啥关系?

在Spacer中遍历cells数组时给每个Cell设置的key值是index!!!,react会根据key来判断是否重构和删除,因为c2删除了c3的index值上升了一位,因此实际上c3的props用的还是c2的,但于此同时又手动设置一遍c3的props,这对c3来说相当于一次props更新,于是就又重绘了一次。假如现在还有这四个组件,我们删除掉c1,则c2,c3,c4将各自重绘一遍。

为避免这种无必要的重绘,只需把key的值和name保持一直即可,设置key=name,那么一切即正常了。

this.state.cells.map(({name,x,y},index) =>
            <Cell name={name} key={name} x={x} y={y} onRemove={(t) => this.onRemove(t)}/>
          )

对于动态数组来说,谨慎设置key尤为重要,这个东西你设错了也没大关系不会影响功能,就是没设置也顶多在控制台打印个警告,但是数组一大,还是很影响性能的。

CSS Module的一个小问题

使用CSS Module也有两个月了,整体上感觉良好。因为是用的webpack导入样式,有个小问题:

引用第三方库时如果他需要引用自己的css文件,那么就不能用webpack导入

有两个解决方法:

  • 直接在index.html中用link方式引入
  • 不对原生css文件进行css module处理,可以用sass、less预处理来写样式然后再进行module处理

目前采用的是第二种方式,so far so good。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.