Nagging little questions about my React - Game of Life program

Nagging little questions about my React - Game of Life program
0

#1

I’ve finished it and am pleased with it. (Thank you to PortableStick, RadDog25, and honmanyau for helping me to understand the vagaries of React better.)

There are just a few things that continue to bother me.

  1. Why are there two arrows on the “Presets” dropdown?
  2. I created a bunch of cells and used the width of the container to wrap them and force them into rows. This seems like “not the best way to do it”. I’ve seen others do it, but still. I thought about having a component called Row into which I would put the Cells. Then I could have put in some extra divs to control the flow more directly. Is there a more elegant way to do this? I’m not looking for someone to rewrite my code, just to give me an idea of a better approach.
  3. When creating this container box to get the rows to wrap properly, it should be simple math, right? The number of cells times the size of the cells. But that math didn’t work because when I zoom out, it is not enough. What was wrong?
  4. When the start button changes color (from start to stop), it does it with a fade/wipe. Is that normal?
  5. For the love of Pete, why won’t the board center perfectly? (If I ever write a web dev memoir, it will be titled Why the Eff Won’t This Thing Center?!? (I ended up forcing to center my putting a right margin of 6% on it - but that’s cheating.)
  6. Why does the Controls.render get called on each iteration? (Shown with a console.log statement). None of the state variables passed to it are getting changed on each iteration. My understanding was that components only redraw when their rendering data changes, because of a change in their props.
  7. I tried letting the user to drag his mouse across many squares to “select” them. It sort of works, but it is laggy.

Thanks, have a look, let me know what you think. Constructive criticism is welcome.

Regards,
Kevin

EDIT:

Forgot to include a link.


#2

I remember having mine in a Row component at first, and performance was abysmal. I think that every time the cell data changed, it was re-rendering the whole row. I think that the way you’re doing it is the most practical approach.

Could you post a link to your project here? I know where I could find it, but I’m sooooo laaaazy.


#3

Could you post a link to your project here? I know where I could find it, but I’m sooooo laaaazy.

No, that was an oversight on my part. Sorry.


#4

This one is really hurting my brain. React-bootstrap requires you to use a Bootstrap stylesheet in addition to their own components. Even more unwise is that they’re not opinionated about which version to use. The end result is that you’ve got two libraries doing the same thing in different ways. React-bootstrap defines the caret as an element in their dropdownButton component, while the new version of Bootstrap defines the caret using the ::after pseudo-element. I think the easiest solution is a bit of a hack, but just disable the caret in Sass:

.caret
  display: none

Scaling gets all screwy when element sizes are defined in px. Defining size in terms of em is better, but still complicated since 1em equals the font size of the nearest font-size definition, which can be difficult to keep track of. In this case, sizing everything by rem may get you the results you want. Long story short, getting the whole thing to scale perfectly would be really hard, I think.

My guess would be that it’s just rendering slowly because there’s a lot for the browser to handle, but when I look at the performance profiler it looks good. So, idunno. Not normal, though.

This understanding is probably my fault, since I think it’s what I posted in your other topic. Turns out, it’s not entirely accurate. While React will indeed update a component only if it’s changed, it will still call render() to see if the output is any different. I’m not entirely sure why it keeps rendering, though, as the solution in the article I linked doesn’t stop it. I was able to stop it from rendering by changing Controls to a functional stateless component. That stopped it from rendering over and over again while keeping functionality. Here’s my change:

function Controls(props) {
    const onPresetSelect = (id,event) => props.handlePreset(id);
    const onStartClick = () => props.handleStart()
    const onSpeedClick = (speed,event) => props.handleSpeed(speed)
    const onColorClick = (color,event) => props.handleColor(color)
    const onClearClick = () => props.handleClear()
    const onRandomClick = () => props.handleRandom()
 
    const presetsMenuList = props.presets.map((preset, i) => <MenuItem eventKey={i} onClick={onPresetSelect.bind(this, i)}>{preset.name}</MenuItem>)
    console.log("Controls.render");

    return (
      <div className="center">
        <Button id="start" bsStyle={(props.isRunning)?"danger":"success"} onClick={onStartClick}>{(props.isRunning)?"Stop":"Start"}</Button>
        &nbsp;&nbsp;&nbsp;
        <ButtonGroup>
          <Button id="speed-slow" bsStyle="success" active={props.speed==1000} onClick={onSpeedClick.bind(this, "slow")}>Slow</Button>
          <Button id="speed-medium" bsStyle="success" active={props.speed==500} onClick={onSpeedClick.bind(this, "medium")}>Medium</Button>
          <Button id="speed-fast" bsStyle="success" active={props.speed==100} onClick={onSpeedClick.bind(this, "fast")}>Fast</Button>
        </ButtonGroup>
        &nbsp;&nbsp;&nbsp;
        <Button id="speed-slow" bsStyle="warning" onClick={onClearClick}>Clear</Button>
        &nbsp;
        <Button id="speed-medium" bsStyle="warning" onClick={onRandomClick}>{(props.isRunning)?"Shotgun":"Random"}</Button>
        &nbsp;
        <DropdownButton bsStyle="warning" title="Presets" dropup id="presets-button">
          {presetsMenuList}
        </DropdownButton>
        &nbsp;&nbsp;&nbsp;
        <ButtonGroup>
          <Button id="color-rainbow" bsStyle="info" active={props.color=="rainbow"} onClick={onColorClick.bind(this, "rainbow")}>Rainbow</Button>
          <Button id="color-red" bsStyle="info" active={props.color=="red"} onClick={onColorClick.bind(this, "red")}>Red</Button>
          <Button id="color-gray" bsStyle="info" active={props.color=="gray"} onClick={onColorClick.bind(this, "gray")}>Grayscale</Button>
        </ButtonGroup>
        <br/><br/>
      </div>
    )
  }

This is just a function that, when called, returns some JSX. This is what most React components should look like, even though most React tutorials make a much bigger deal out of the full component class.

Hope that helps.


#5

The end result is that you’ve got two libraries doing the same thing in different ways. React-bootstrap defines the caret as an element in their dropdownButton component, while the new version of Bootstrap defines the caret using the ::after pseudo-element. I think the easiest solution is a bit of a hack, but just disable the caret in Sass:

Makes sense. It’s sloppy on React Bootstraps part, but your hack makes sense.

While React will indeed update a component only if it’s changed, it will still call render() to see if the output is any different.

Interesting. I notice that Header and Footer aren’t being called each iteration though. I guess, because they are not children of Game (where I hold the state), React knows not to bother checking them. Since Controls is a child of Game, React needs to check it and that’s how it does it, running render to check it against the virtual DOM to decide if it needs to change the browser. Interesting. I guess it’s harmless. But that’s good info to know - there may be situations where that could cause performance issues.

Thanks for the info.