我有使用ReactJS呈现的按钮,其onClick
绑定到以prop
传入的函数。单击一个按钮时,它会调用一个函数,该函数设置pushState
然后呈现一个新组件。这很好,但回到第一页后,按钮停止响应点击。
// _init.js.coffee
window.TD or= {}
# Rendering
render_fan = ->
window.history.pushState({}, "Fan Demo | Tunetap", '/fan')
render('fan')
render_artist = ->
window.history.pushState({}, "Artist Demo | Tunetap", '/artist')
render('artist')
render_venue = ->
window.history.pushState({}, "Venue Demo | Tunetap", '/venue')
render('venue')
render = (arg) ->
target = document.getElementById('content')
role_children = { render_fan: render_fan, render_artist: render_artist, render_venue: render_venue }
if arg == 'root'
React.renderComponent(TD.Root(role_children), target)
else if arg == 'fan'
React.renderComponent(TD.FanRoot(role_children), target)
else if arg == 'artist'
React.renderComponent(TD.ArtistRoot(role_children), target)
else if arg == 'venue'
React.renderComponent(TD.VenueRoot(role_children), target)
else render_404()
render_404 = -> React.renderComponent(TD.Error404(), document.getElementById('content'))
# Routing
pathname = window.location.pathname.slice(1)
if pathname.length < 1
render('root')
else if pathname == 'fan' || pathname == 'artist' || pathname == 'venue'
render(pathname)
else render_404()
// root.js.coffee
window.TD or= {}
TD.Root = React.createClass
render: ->
React.DOM.div
className: 'container'
children: [
React.DOM.div
className: 'row page-header'
children: [
React.DOM.h1
children: 'Tunetap demo'
React.DOM.p
children: 'Select a role to get started'
]
React.DOM.div
className: 'row'
children: [
React.DOM.div
className: 'col-sm-4'
children:
React.DOM.button
className: 'btn btn-default col-sm-10 col-sm-offset-1'
children: 'Fan'
onClick: @props.render_fan
React.DOM.div
className: 'col-sm-4'
children:
React.DOM.button
className: 'btn btn-default col-sm-10 col-sm-offset-1'
children: 'Artist'
onClick: @props.render_artist
React.DOM.div
className: 'col-sm-4'
children:
React.DOM.button
className: 'btn btn-default col-sm-10 col-sm-offset-1'
children: 'Venue'
onClick: @props.render_venue
]
]
TD.FanRoot = React.createClass
render: ->
React.DOM.p
children: 'Fan root'
TD.ArtistRoot = React.createClass
render: ->
React.DOM.p
children: 'Artist root'
TD.VenueRoot = React.createClass
render: ->
React.DOM.p
children: 'Venue root'
答案 0 :(得分:0)
感谢您的现场演示。我已经确定这是React 0.8和Rails的Turbolinks之间存在问题的互动。以下是对正在发生的事情的总结:
在初始页面加载时,将评估JavaScript文件,该文件将加载jQuery,jquery-ujs,Turbolinks,React和您的应用程序代码。运行初始渲染代码,将Root
组件呈现为#content
。因为React依赖事件委托来提高性能,所以它将事件处理程序附加到文档中。
当您点击“粉丝”按钮时,会调用render_fan
来推送/fan
的历史记录条目并呈现FanRoot
组件,替换现有的#content
子组件{1}}。
当您点击后退按钮时,您的浏览器会将网址设置回/
,并触发Turbolinks捕获的popstate
事件。 Turbolinks会恢复<body>
标记的原始内容,causes the linked script to be reevaluated,因为您的JS已加载到页面正文而不是头部。
这会导致重新运行所有JS,导致第二个单独的React副本被初始化(并导致您的应用程序代码再次运行,这是Root组件被重新呈现的方式)。 React的第二个副本会将自己的事件侦听器附加到文档中,但是React 0.8有一个错误,其中React的第二个副本不会添加自己的事件侦听器,所以只有React的第一个副本才会收到点击事件,但它没有知道第二个React存储的onClick处理程序,所以没有任何反应。
较新版本的React没有这个问题 - 它们能够保持封装的单独版本,因此每个React实例都会正确保留自己的事件处理程序。我用React 0.10.0测试了你的应用程序,它运行正常。
然而,我相信您在这里使用Turbolinks是不正确的,并可能在将来导致您遇到问题。听起来好像正确使用Turbolinks,你应该把脚本元素放在你的页面<head>
中,但是因为看起来你在React中构建一个单页应用程序,你可能想要完全禁用Turbolinks并且只是绑定单击后退按钮以重新渲染popstate
。