George Mauer
George Mauer

Reputation: 122062

Why isn't my reactJs re-rendering

I'm really tired of model-binding and am trying to get started with React as I really like the whole stateless idea. I went through the tutorial and it seems straightforward enough.

However, in my own app I am confused why my component isn't re-rendering on state change. Here is the entirety of my app in coffeescript (_ helpers from lodash).

mapObject = _.compose _.object, _.map

racers = mapObject ['red', 'blue', 'green'], (name) -> 
    [name, (key: name, class: name, position: 0)]

advance = (character) ->
    racers[character].position += 5;
    console.log character, "position is", racers[character].position
    view.setState racers: racers

R = React.DOM

Racer = React.createClass 
    getInitialState: -> @props
    render: ->
        R.div (className: 'racer '[email protected], style: (left: @state.position)), ""[email protected]

Racelane = React.createClass render: -> 
    R.li (onClick: _.partial advance, @props.key), Racer @props

Racetrack = React.createClass 
    getInitialState: -> @props
    render: ->
        R.ul (className: 'lanes'), _.map @state.racers, Racelane

view = React.renderComponent (Racetrack racers: racers), (document.querySelector '#racetrack')

Here it is live

we basically have 3 divs in 3 lanes. As you click on each lane each div is supposed to move across it (the left inline style is adjusted).

I define an advance method that modifies my racers object and then calls setState on my view root. And the position...does not change.

I know I'm on the right track, if instead of changing the position I remove or add a racer it works as it should - but it doesn't re-render one level down. What am I doing wrong?

Upvotes: 3

Views: 602

Answers (2)

ritmatter
ritmatter

Reputation: 3498

I think the easiest way to make sure a component redraws is by changing the key attribute. Any change to the key of a element will force it to redraw entirely. If you make the key value dependent on the props, that will also solve the problem.

Upvotes: 0

hugomg
hugomg

Reputation: 69934

When you call setState on the root RaceTrack component it will trigger a redraw and pass the new racer positions to the Racer components via props. However, these new positions end up being ignored: When the racers are first created you are storing their initial position in their internal state and you are rendering the Racer components based on this internal state, which never gets updated.

One quick fix is to change the racers to render based on their props instead of state.

http://jsbin.com/bilejeyu/1/edit

Racer = React.createClass 
    render: ->
        R.div (className: 'racer '[email protected], style: (left: @props.position)), ""[email protected]

Wrapping up, I think the biggest lesson here is that when working with React, you should try to avoid redundant state. Having the root component be the only one with state and use props for everything one is a common pattern.

Upvotes: 4

Related Questions