我真的厌倦了模型绑定,并试图开始使用React,因为我非常喜欢整个无状态的想法。我完成了教程,看起来很简单。
然而,在我自己的应用程序中,我很困惑为什么我的组件不会在状态更改时重新呈现。这是我在coffeescript中的全部应用程序(来自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 '+@state.class, style: (left: @state.position)), ""+@state.position
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')
我们在3个车道中基本上有3个div。当你点击每个泳道时,每个div应该在它上面移动(调整左内联样式)。
我定义了一个advance方法,它修改我的racers对象,然后在我的视图根上调用setState。而且这个位置......并没有改变。
我知道我在正确的轨道上,如果不是改变我移除的位置或添加一个它应该工作的赛车 - 但它不会重新渲染一个级别。我做错了什么?
答案 0 :(得分:4)
当您在根setState
组件上调用RaceTrack
时,它会触发重绘并通过道具将新的赛车位置传递给Racer
组件。但是,这些新位置最终会被忽略:首次创建游戏时,您将其初始位置存储在其内部状态,并且您将基于此内部状态呈现Racer
组件,该状态永远不会更新。
一个快速解决方法是根据道具而不是状态更改要渲染的赛车。
http://jsbin.com/bilejeyu/1/edit
Racer = React.createClass
render: ->
R.div (className: 'racer '+@props.class, style: (left: @props.position)), ""+@props.position
总结一下,我认为这里最重要的一点是,在使用React时,你应该尽量避免冗余状态。让根组件成为唯一一个具有状态并且使用道具的东西,这是一种常见的模式。
答案 1 :(得分:0)
我认为确保重新绘制组件的最简单方法是更改键属性。对元素键的任何更改都将强制它完全重绘。如果你使键值取决于道具,那也将解决问题。