【问题标题】:Click button not triggering "handleSubmit" function in React单击按钮不会触发 React 中的“handleSubmit”功能
【发布时间】:2018-04-15 15:57:48
【问题描述】:

我正在构建一个 react on rails 应用程序。我在页面上有一个按钮,用户可以指示他们是否要加入聚会。单击“加入”按钮应在当前用户和事件之间创建一个 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

【问题讨论】:

    标签: ruby-on-rails forms reactjs


    【解决方案1】:

    render 函数返回之前构建的buttonformbutton。我建议只检查组件的state,避免使用表单(未插入 DOM,因此“提交表单因表单未连接而取消”消息)。

    基本上,如果您使用buttononClick 函数,您的代码会简单得多。您不必处理将触发onSubmit 的按钮类型submitbutton 前者或不触发后者:Difference between <input type='button' /> and <input type='submit' />

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

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

    我尝试在下面的 sn-p 中修改您的代码,希望这会有所帮助!

    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')
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <div id="container">
        <!-- This element's contents will be replaced with your component. -->
    </div>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-30
      • 2021-12-08
      • 2016-04-05
      • 1970-01-01
      • 2012-01-19
      相关资源
      最近更新 更多