【问题标题】:Every element rerenders with react using redux?每个元素都使用 redux 重新渲染?
【发布时间】:2018-01-02 10:15:57
【问题描述】:

JSFiddle

var gridWidth = 15;
var gridHeight = 15;

var grid = [];
for(var y=0; y<gridHeight; y++) {
    grid.push([]);
    for(var x=0; x<gridWidth; x++) {
        grid[y][x] = {c:0};
    }
}

var reducer = function(state = grid, action) {
  let newState = clone(state);
  if(action.type==='CC') {
    newState[action.payload.y][action.payload.x].c = action.payload.c;
  }
  return newState;
}
var store = Redux.createStore(reducer);

var colours = ['black', 'grey'];
var Provider = ReactRedux.Provider;
var connect = ReactRedux.connect;
var map = function(state) {
    return {grid:state};
}

var Box = React.createClass({
    width: 15,
    handleClick: function(x, y) {
        this.props.dispatch({type:'CC', payload: {c:1, x:x, y:y}});
    },
    render: function() {
        console.log('boxrender')
        var pos = {
          top: this.props.y * this.width,
          left: this.props.x * this.width,
          width: this.width,
          height: this.width,
          background: this.props.colours[this.props.box.c]
        }
        return <div className="box" style={pos} onMouseOver={() => this.handleClick(this.props.x, this.props.y)}></div>
    }
});
var ConnectedBox = connect(map)(Box);

var Grid = React.createClass({

  render: function() {
    console.log('grid render')
    return (
      <div>
        {this.props.grid.map((row, y) => {
          return row.map((box, x) => {
            return <ConnectedBox key={'x'+x+'y'+y} box={box} x={x} y={y} colours={this.props.colours} />;
          })
        })}
      </div>
    )
  }
});
var ConnectedGrid = connect(map)(Grid);

ReactDOM.render(
    <Provider store={store}>
      <ConnectedGrid colours={colours} />
    </Provider>,
    document.getElementById('container')
);

我有一个大网格,我希望能够在鼠标悬停时“着色”,使用 redux 进行更改,但是即使只更改了一个框对象,react 每次都会重新渲染每个框变化,我不知道为什么?这让它变得超级慢

【问题讨论】:

    标签: reactjs redux react-redux


    【解决方案1】:

    优化:https://jsfiddle.net/p6z5veo6/5/


    React 的基本性能规则

    • React.PureComponentReact.Component 与自定义shouldComponentUpdate 一起使用
    • 只将 store 中需要的部分传递给您的组件
    • 如果 props 或 state 没有改变,请避免重新渲染
    • 避免在每次渲染时创建对象和绑定函数的新实例(当() =&gt; {} 传递给onClick 等时经常发生)

    我做了什么以及为什么

    • GridBox 组件实现了自定义shouldComponentUpdate

      class Box extends React.Component {
        shouldComponentUpdate(nextProps) {
          return nextProps.colour !== this.props.colour;
        }
      
      // ...
      
      class Grid extends React.Component {
        shouldComponentUpdate(nextProps) {
          return false;
        }
      
    • 在这种情况下,Grid 组件不必在每次更新 store 时都重新渲染,因为我们只想重新渲染特定的 Box 组件,因此我们仅将 Grid 用于初始渲染并传递仅从商店到Box的相关数据

      const ConnectedBox = connect((store, { x, y }) => ({
        colour: store[y][x].c
      }))(Box);
      
    • 实现了简化器的更简单版本,只需更新包含新颜色的主要引用和对象

      var reducer = (state = grid, action) => {
        if (action.type === "CC") {
          const { x, y, c } = action.payload;
      
          const newState = [...state];
          newState[y][x] = { c };
      
          return newState;
        }
      
        return state;
      };
      
    • 在构造函数中绑定handleClick

      class Box extends React.Component {
        constructor(props) {
          super(props);
      
          this.width = 15;
          this.handleClick = this.handleClick.bind(this);
        }
      

    非常相似的项目在文章中实现和描述:An artificial example where MobX really shines and Redux is not really suited for it

    文章中项目的存储库也是available on github。您可以read articlecheck repothis pull request,这样您就可以了解最终如何更好地改进您的代码,因为问题在于您决定用于存储在 redux 中的数据结构(数组)。

    【讨论】:

    • 感谢您的彻底回答,这很棒,让我有很多思考和尝试的新方法。你的小提琴要快得多,我可以看到它只渲染正方形;如果我将网格提升到更像 150x250 的尺寸,它仍然不可避免地会变慢,但我会继续努力!
    • 还要检查这个答案stackoverflow.com/questions/34782249/…,它提出了两个有趣的解决方案:自定义connect HOC 和使用不同的数据结构。
    【解决方案2】:

    您正在呈现一个列表列表,请尝试将每个内部列表包装在 div 中,以便获得正确的 key

    {
      this.props.grid.map((row, y) => 
        <div key={y}>
          {
            row.map((box, x) => 
              <ConnectedBox key={'x'+x+'y'+y} box={box} x={x} y={y} colours={this.props.colours} />)
          }
        </div>)
    }
    

    【讨论】:

      【解决方案3】:

      我看不出是什么原因造成的,但如果您只需要快速修复,您可以添加 shouldComponentUpdate 以防止其呈现,除非 box.c 更改:

      var Box = React.createClass({
        shouldComponentUpdate(nextProps) {
          return this.props.box.c !== nextProps.box.c;
        },
      

      工作小提琴:https://jsfiddle.net/5c21yw3j/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-03
        • 1970-01-01
        • 2016-05-17
        • 1970-01-01
        • 2017-09-22
        • 2020-11-27
        相关资源
        最近更新 更多