我正在建立对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
答案 0 :(得分:0)
在button
函数中返回之前构建的render
是form
或button
。我建议只需检查组件的state
,避免使用表单(未插入DOM,因此&#34;提交表单已取消,因为表单未连接&#34;消息)。< / p>
基本上,如果您使用onClick
的{{1}}函数,您的代码会更简单。您不必处理按钮类型button
或submit
,这些按钮类型将针对前者触发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
)也这样做。
我试着在下面的代码片段中修改一下你的代码,希望这会有所帮助!
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;