点击按钮不触发" handleSubmit" React

时间:2017-11-03 01:09:24

标签: ruby-on-rails forms reactjs

我正在建立对rails app的反应。我在页面上有一个按钮,用户可以指示他们是否要加入聚会。点击"加入"按钮应该在当前用户和事件之间创建一个rsvp关系,按钮将切换到"离开",如果用户然后点击"离开"按钮,这个关系将从rails后端删除。在弄乱我的反应组件后,我的"加入"按钮不会触发" onSubmit"功能,"离开"按钮似乎返回错误说"提交表单已取消,因为表单未连接"。如果有人能帮助我清理我的逻辑,我会非常感激。

import React from 'react'

class EventsIndexContainer extends React.Component {
 constructor(props) {
 super(props)
 this.state = {
  active: props.rsvp
 }
 this.toggleButton = this.toggleButton.bind(this)
 this.handleRsvpSubmit = this.handleRsvpSubmit.bind(this)
 this.handleRsvpDelete = this.handleRsvpDelete.bind(this)
}

toggleButton() {
 this.setState({active: !this.state.active})
}

handleRsvpSubmit(event) {
 event.preventDefault()
 let formPayLoad = {
  user_id: this.props.current_user.id,
  event_id: this.props.selectedId
 }
 this.props.addRsvp(formPayLoad)
}

handleRsvpDelete() {
 fetch(`/api/v1/rsvps/${this.props.selectedId}`, {
  method: 'DELETE'}
 )
}

render() {
 let button
 let joinButton =
 <form onSubmit={this.handleRsvpSubmit}>
  <button type="button" onClick={() => (this.props.handleSelect(), 
  this.toggleButton())}>Join</button>
 </form>

 let leaveButton =
  <button type="button" onClick={() => (this.toggleButton(), 
  this.handleRsvpDelete)}>Leave</button>

 button = this.state.active? leaveButton : joinButton

 return(
   <div>
      <h4>{this.props.location} - {this.props.meal_type} at 
      {this.props.time}</h4>
      <p>{this.props.group.name}</p>
      {button}
      <button>See who is going</button>
  </div>
 )
}
}

export default EventsIndexContainer

这是父容器:

import React from 'react'
import GroupIndexContainer from './GroupIndexContainer'
import EventsIndexContainer from './EventsIndexContainer'

class MainContainer extends React.Component {
 constructor(props) {
 super(props)
 this.state = {
  groups: [],
  current_user: null,
  events: [],
  rsvps: [],
  selectedId: null
 }
 this.fetchGroups = this.fetchGroups.bind(this)
 this.fetchEvents = this.fetchEvents.bind(this)
 this.handleSelect = this.handleSelect.bind(this)
 this.addRsvp = this.addRsvp.bind(this)
 this.fetchRsvps = this.fetchRsvps.bind(this)
 }

 componentDidMount() {
    fetch('api/v1/users.json', {
      credentials: 'same-origin',
      method: "GET",
      headers: { 'Content-Type': 'application/json' }
    })
    .then(response => response.json())
    .then(data => {
      this.setState ({current_user: data.user})
    })
    .then(this.fetchGroups())
    .then(this.fetchEvents())
    .then(this.fetchRsvps())
  }

  fetchGroups() {
    fetch('/api/v1/groups', {
      credentials: 'same-origin',
      method: "GET",
      headers: { 'Content-Type': 'application/json' }
    })
    .then(response => response.json())
    .then(data => {
      this.setState({groups: data.groups})
    })
  }

  fetchEvents() {
    fetch('/api/v1/events', {
      credentials: 'same-origin',
      method: "GET",
      headers: { 'Content-Type': 'application/json' }
    })
    .then(response => response.json())
    .then(data => {
      this.setState({events: data})
    })
  }

  fetchRsvps() {
    fetch('/api/v1/rsvps', {
      credentials: 'same-origin',
      method: "GET",
      headers: { 'Content-Type': 'application/json' }
    })
    .then(response => response.json())
    .then(data => {
      this.setState({rsvps: data.rsvps})
    })
  }

  handleSelect(id) {
    this.setState({selectedId: id})
  }

  addRsvp(formPayLoad) {
    fetch('/api/v1/rsvps', {
      method: 'POST',
      credentials: 'same-origin',
      headers: { 'Accept': 'application/json', 'Content-Type': 'application/json'},
      body: JSON.stringify(formPayLoad)
    })
  }

  render() {
    let groups = this.state.groups.map((group) => {
      return (
        <GroupIndexContainer
          key={group.id}
          id={group.id}
          name={group.name}
        />
      )
    })

    let rsvp_ids = this.state.rsvps.map(rsvp => rsvp.event_id)
    let events = this.state.events.map((event) => {
      return(
        <EventsIndexContainer
          key={event.id}
          id={event.id}
          rsvp={rsvp_ids.some(rsvp_id => rsvp_id == event.id) ? true : false}
          location={event.location}
          meal_type={event.meal_type}
          time={event.time}
          group={event.group}
          current_user={this.state.current_user}
          user={event.user}
          selectedId={this.state.selectedId}
          addRsvp={this.addRsvp}
          handleSelect={() => this.handleSelect(event.id)}
        />
      )
    })

    return(
      <div className="wrapper">

        <div className="groups-index">
          <h3>Your Groups:</h3>
          {groups}
        </div>

        <div className="events-index">
          <h3>What's happening today...</h3>
          {events}
        </div>

      </div>
    )
  }
}

       export default MainContainer

1 个答案:

答案 0 :(得分:0)

button函数中返回之前构建的renderformbutton。我建议只需检查组件的state,避免使用表单(未插入DOM,因此&#34;提交表单已取消,因为表单未连接&#34;消息)。< / p>

基本上,如果您使用onClick的{​​{1}}函数,您的代码会更简单。您不必处理按钮类型buttonsubmit,这些按钮类型将针对前者触发button或不针对后者触发Difference between <input type='button' /> and <input type='submit' />

此外,在组件属性中使用箭头函数不是一个好习惯,这里也记录了:Why shouldn't JSX props use arrow functions or bind?

所以我建议第二次将你的onSubmit属性更改为onClick,在构造函数中绑定onClick={ this.handleLeave },就像你为其他函数所做的那样,并在那里处理工作(对handleLeave)也这样做。

我试着在下面的代码片段中修改一下你的代码,希望这会有所帮助!

&#13;
&#13;
handleJoin
&#13;
class EventsIndexContainer extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      active: props.rsvp
    }
    this.toggleButton = this.toggleButton.bind(this)
    this.handleRsvpSubmit = this.handleRsvpSubmit.bind(this)
    this.handleRsvpDelete = this.handleRsvpDelete.bind(this)
    
    // Stub
    this.handleSelect = this.handleSelect.bind(this)
  }
  
  handleSelect() {
    console.log("handleSelect called");
  }
  
  toggleButton() {
    this.setState({active: !this.state.active})
  }
  
  // event argument removed here, wasn't used anyway
  handleRsvpSubmit() {
    console.log("handleRsvpSubmit called")
  }
  
  handleRsvpDelete() {
    console.log("handleRsvpDelete called")
  }
  
  render() {
    return(
      <div>
        <h4>Hello</h4>
        <p>Group name</p>
        { this.state.active ?
          <button type="button" onClick={() => (this.toggleButton(), this.handleRsvpDelete())}>Leave</button>
        :
          <button type="button" onClick={() =>(this.handleSelect(),this.toggleButton(), this.handleRsvpSubmit())}>Join</button>
        }
        <button>See who is going</button>
      </div>
      )
    }
  }
  
ReactDOM.render(
  <EventsIndexContainer rsvp={ false } />,
  document.getElementById('container')
);
&#13;
&#13;
&#13;