Abby Abby - 1 year ago 167
React JSX Question

Every element rerenders with react using 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')
);


I have a large grid that I want to be able to 'colour in' on mouseover, using redux to make the changes, however even though only one box object is being changed, react is re-rendering every box each time one changes and I don't know why? It's making it super slow

Answer Source

Optimized: https://jsfiddle.net/p6z5veo6/5/


Basic perf rules for React

  • Use React.PureComponent or React.Component with custom shouldComponentUpdate
  • Pass only needed slice of the store to your components
  • Avoid re-rendering if props or state has not changed
  • Avoid creating new instances of objects and binding functions on each render (very often happens when () => {} is pass to onClick etc.)

What I did and why

  • Implemented custom shouldComponentUpdate for Grid and Box components

    class Box extends React.Component {
      shouldComponentUpdate(nextProps) {
        return nextProps.colour !== this.props.colour;
      }
    
    // ...
    
    class Grid extends React.Component {
      shouldComponentUpdate(nextProps) {
        return false;
      }
    
  • In this case Grid component doesn't have to be re-rendered every time when store is updated because we want to re-render only specific Box component so we use Grid only for initial rendering and pass only relevant data from the store to Box

    const ConnectedBox = connect((store, { x, y }) => ({
      colour: store[y][x].c
    }))(Box);
    
  • Implemented simpler version of your reducer, just update main reference and object which contain new colour

    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;
    };
    
  • Bind handleClick in costructor

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

Very similar project was implemented and described in the article: An artificial example where MobX really shines and Redux is not really suited for it.

Repository of the project from article is also available on github. You can read article, check repo and this pull request so you can learn how eventually could you more improve your code because the problem is with the data structure (array) that you decided to use to store in redux.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download