每个元素都使用redux进行反应?

时间:2017-07-26 21:46:01

标签: reactjs redux react-redux

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进行更改,但是即使只更改了一个box对象,每次重复渲染每个框变化,我不知道为什么?这让它变得非常缓慢

3 个答案:

答案 0 :(得分:1)

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

React的基本性能规则

  • 使用React.PureComponentReact.Component与自定义shouldComponentUpdate
  • 仅将商店所需的切片传递给您的组件
  • 如果道具或州没有改变,则避免重新渲染
  • 避免在每个渲染上创建对象和绑定函数的新实例(通常在() => {}传递给onClick时发生等。)

我做了什么以及为什么

  • shouldComponentUpdateGrid组件实施自定义Box

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

    Box
  • 实现了简化版的简化版,只需更新包含新颜色的主参考和对象

    const ConnectedBox = connect((store, { x, y }) => ({
      colour: store[y][x].c
    }))(Box);
    
  • 在costructor中绑定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

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

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

答案 1 :(得分:0)

您正在呈现列表列表,尝试将每个内部列表包装在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>)
}

答案 2 :(得分:0)

我一眼就看不到导致它的原因,但是如果你只是需要快速修复,你可以添加shouldComponentUpdate以防止它呈现,除非box.c发生变化:

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

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