从pushstate返回时,FB React onClick不起作用

时间:2014-04-01 03:28:52

标签: javascript pushstate reactjs

我有使用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'

1 个答案:

答案 0 :(得分:0)

感谢您的现场演示。我已经确定这是React 0.8和Rails的Turbolinks之间存在问题的互动。以下是对正在发生的事情的总结:

  1. 在初始页面加载时,将评估JavaScript文件,该文件将加载jQuery,jquery-ujs,Turbolinks,React和您的应用程序代码。运行初始渲染代码,将Root组件呈现为#content。因为React依赖事件委托来提高性能,所以它将事件处理程序附加到文档中。

  2. 当您点击“粉丝”按钮时,会调用render_fan来推送/fan的历史记录条目并呈现FanRoot组件,替换现有的#content子组件{1}}。

  3. 当您点击后退按钮时,您的浏览器会将网址设置回/,并触发Turbolinks捕获的popstate事件。 Turbolinks会恢复<body>标记的原始内容,causes the linked script to be reevaluated,因为您的JS已加载到页面正文而不是头部。

    这会导致重新运行所有JS,导致第二个单独的React副本被初始化(并导致您的应用程序代码再次运行,这是Root组件被重新呈现的方式)。 React的第二个副本会将自己的事件侦听器附加到文档中,但是React 0.8有一个错误,其中React的第二个副本不会添加自己的事件侦听器,所以只有React的第一个副本才会收到点击事件,但它没有知道第二个React存储的onClick处理程序,所以没有任何反应。

  4. 较新版本的React没有这个问题 - 它们能够保持封装的单独版本,因此每个React实例都会正确保留自己的事件处理程序。我用React 0.10.0测试了你的应用程序,它运行正常。

    然而,我相信您在这里使用Turbolinks是不正确的,并可能在将来导致您遇到问题。听起来好像正确使用Turbolinks,你应该把脚本元素放在你的页面<head>中,但是因为看起来你在React中构建一个单页应用程序,你可能想要完全禁用Turbolinks并且只是绑定单击后退按钮以重新渲染popstate