我目前正在尝试使用Reactjs从一个类返回多个按钮。目前,我可以让所有按钮返回,但是onClick
函数仅在要显示的最后一个按钮上起作用。如果有人可以帮助它,我们将不胜感激。这是重要的代码行。
let GroupCollection2 = db.collection('groups');
GroupCollection2.get()
.then(snapshot => {
snapshot.forEach(doc => {
if(doc.get('ModuleCode') === document.getElementById("groupSearch").value)
{
document.getElementById("groupDisplayError").innerHTML = "";
if(found === false){
document.getElementById("groupDisplayTable").innerHTML = '<tr id="groupDisplayTableHeader"><th>Group Name</th><th>Module Code</th><th>Join Or View Group</th></tr>';
}
found = true;
document.getElementById("groupDisplayTable").innerHTML += "<tr><td>"+doc.id+"</td><td>"+doc.data().ModuleCode+"</td><td class='groupDisplayTableButton'></td></tr>";
ReactDOM.render(<Button command={doc.id} />, document.getElementsByClassName('groupDisplayTableButton')[count]);
count++;
}
});
if(found === false){
document.getElementById("groupDisplayError").innerHTML = "No Results.";
}
})
.catch(err => {
console.log('Error getting documents', err);
});
和
class Button extends React.Component{
joinGroup(command){
alert(command);
}
render(){
return(<button onClick={this.joinGroup.bind(this, this.props.command ) }>Join Group</button>);
}
}
整个代码在这里:
import React from "react";
import ReactDOM from 'react-dom';
import { compose } from "redux";
import { connect } from "react-redux";
import { signout } from "../store/actions/auth";
import requireAuth from "./hoc/requireAuth";
import firebase from "../services/firebase.js";
import Calendar from "./Planner.js"
//<Calendar />
var db = firebase.firestore();
const Main = ({ signout }) => {
return (
<div id="homePage" className="container">
<div className="row">
<div class="col s6" id="createPage">
<form id="createGroup">
<i className="large material-icons prefix search-icon">group_add</i>
<div className="row">
<div className="col s12">
<div className="row">
<div className="input-field col s12 vert-align">
<input type="text" id="cgroupName" name="groupName"/>
<label htmlFor="cgroupName">Group Name</label>
</div>
</div>
<div className="row">
<div className="input-field col s12 vert-align">
<input type="text" id="cgroupModuleCode" name="moduleCode"/>
<label htmlFor="cgroupModuleCode">Module Code</label>
</div>
</div>
<div className="row">
<input type="button" value="Create Group" onClick={ ()=> createGroup()}/>
</div>
<p id="groupCreateError"></p>
</div>
</div>
</form>
</div>
<div className="col s6">
{/*<script src="https://www.gstatic.com/firebasejs/3.1.0/firebase-database.js"></script>*/}
{/* Renders the search bar */}
<i className="large material-icons prefix search-icon">group</i>
<div className="row">
<div className="col s12">
<div className="row">
<div className="input-field col s12 vert-align">
<i className="material-icons prefix search-icon">search</i>
<input type= "text" id ="groupSearch" name="searchGroup"/>
<label htmlFor="groupSearch">Search For A Group</label>
<a className="waves-effect waves-teal btn-flat search-btn" onClick={ ()=> searchGroups()}>Search</a>
</div>
</div>
</div>
</div>
{/* Display any searched groups here */}
<div class="row" id="groupDisplay">
<p id="groupDisplayError"></p>
<table id="groupDisplayTable">
</table>
</div>
</div>
</div>
<button onClick={ () => profile()} hidden>Profile</button>
<button className="btn-switch" onClick={() => signout()}>Log Out</button>
</div>
);
};
function mapStateToProps(state) {
return {
auth: state.firebaseReducer.auth
};
}
function mapDispatchToProps(dispatch) {
return {
signout: () => dispatch(signout())
};
}
function profile(){
}
function logOut(){
document.getElementById("navbar").style.display = "none";
signout();
}
function searchGroups(){
if(document.getElementById("groupSearch").value === ""){
document.getElementById("groupDisplayError").innerHTML = "Please enter a value and try again.";
}
else{
var found = false;
var count = 0;
let GroupCollection = db.collection('groups').doc(document.getElementById("groupSearch").value);
GroupCollection.get()
.then(doc => {
if (doc.exists) {
found = true;
document.getElementById("groupDisplayError").innerHTML = "";
document.getElementById("groupDisplayTable").innerHTML = '<tr id="groupDisplayTableHeader"><th>Group Name</th><th>Module Code</th><th>Join Or View Group</th></tr>';
document.getElementById("groupDisplayTable").innerHTML += "<tr><td>"+doc.id+"</td><td>"+doc.data().ModuleCode+"</td><td class='groupDisplayTableButton'></td></tr>";
ReactDOM.render(<Button command={doc.id}/>, document.getElementsByClassName('groupDisplayTableButton')[count]);
count++;
}
})
.catch(err => {
document.getElementById("groupDisplayError").innerHTML = "Error getting document: "+err;
});
let GroupCollection2 = db.collection('groups');
GroupCollection2.get()
.then(snapshot => {
snapshot.forEach(doc => {
if(doc.get('ModuleCode') === document.getElementById("groupSearch").value)
{
document.getElementById("groupDisplayError").innerHTML = "";
if(found === false){
document.getElementById("groupDisplayTable").innerHTML = '<tr id="groupDisplayTableHeader"><th>Group Name</th><th>Module Code</th><th>Join Or View Group</th></tr>';
}
found = true;
document.getElementById("groupDisplayTable").innerHTML += "<tr><td>"+doc.id+"</td><td>"+doc.data().ModuleCode+"</td><td class='groupDisplayTableButton'></td></tr>";
ReactDOM.render(<Button command={doc.id} />, document.getElementsByClassName('groupDisplayTableButton')[count]);
count++;
}
});
if(found === false){
document.getElementById("groupDisplayError").innerHTML = "No Results.";
}
})
.catch(err => {
console.log('Error getting documents', err);
});
}
}
function createGroup(){
let GroupCollection = db.collection('groups').doc(document.getElementById("cgroupName").value);
GroupCollection.get()
.then(doc => {
if (!doc.exists) {
document.getElementById("groupCreateError").innerHTML = "Group created sucessfully.";
const GroupCollection2 = db.collection('groups');
GroupCollection2.doc(document.getElementById("cgroupName").value).set({
ModuleCode:document.getElementById("cgroupModuleCode").value,
Timetable: "",
User0: firebase.auth().currentUser.email,
User1: "",
User2: "",
User3: "",
User4: "",
User5: "",
User6: "",
User7: "",
User8: "",
User9: "",
})
} else {
document.getElementById("groupCreateError").innerHTML = "Group Name Already Exists.";
}
})
.catch(err => {
document.getElementById("groupCreateError").innerHTML = "Error getting document: "+err;
});
}
class Button extends React.Component{
joinGroup(command){
alert(command);
}
render(){
return(<button onClick={this.joinGroup.bind(this, this.props.command ) }>Join Group</button>);
}
}
export default compose(
connect(
mapStateToProps,
mapDispatchToProps
),
requireAuth
)(Main);
答案 0 :(得分:0)
您可能必须确保每个按钮都是唯一键。在这种情况下,可以使用doc.id。因此,您将需要添加一个关键道具,如下所示:
ReactDOM.render(<Button command={doc.id} key={doc.id} />,
document.getElementsByClassName('groupDisplayTableButton')[count]);
如果您可能有多个相同的doc.id,则可以修改键以包括计数,以确保每个按钮都有唯一的键。即key = {doc.id + count}
答案 1 :(得分:0)
我认为您没有正确绑定joinGroup函数。尝试用以下功能组件替换Button类:
const Button = ({ command }) => {
const joinGroup = _command => alert(_command);
return (
<button type="button" key={command} onClick={() => joinGroup(command)}>
Join Group
</button>
);
};
答案 2 :(得分:0)
不幸的是,我没有解决方案。也就是说,我绝对认为这是问题所在:ReactDOM.render(<Button command={doc.id} />, document.getElementsByClassName('groupDisplayTableButton')[count]);
。
请勿在应用程序内部使用ReactDOM.render
,将按钮呈现给其父级(在本例中为表格)。您无法完全做到这一点,因为该表不存在,因为您正在向DOM中手动添加元素。
在试图弄清楚发生了什么的过程中,我最终重构了一半的代码。以为我会分享它,以防万一。
Here is a sandbox to show that the click handler works with multiple table buttons。
我删除了搜索功能,并模拟了Firebase。
import React, { useState } from "react";
import ReactDOM from "react-dom";
function App() {
return <Main />;
}
const Main = () => {
// fake firebase mock
const [firebaseMock, setFirebaseMock] = useState("");
// input fields
const [groupName, setGroupName] = useState("");
const [moduleCode, setModuleCode] = useState("");
// error messages
const [errorMessage, setErrorMessage] = useState("");
const createGroup = (_groupName, _moduleCode) => {
// ensure user submist a group name and a module code
if (!_groupName || !_moduleCode) {
setErrorMessage("You must provide a group name and a module code.");
return;
}
// if group already exists with the same name, create an error message
if (Object.keys(firebaseMock).includes(_groupName)) {
setErrorMessage("Group Name Already Exists.");
return;
}
setFirebaseMock({
...firebaseMock,
[_groupName]: { ModuleCode: _moduleCode }
});
// clear inputs
setGroupName("");
setModuleCode("");
};
return (
<div id="homePage" className="container">
<div className="row">
<div class="col s6" id="createPage">
<form id="createGroup">
<i className="large material-icons prefix search-icon">group_add</i>
<div className="row">
<div className="col s12">
<div className="row">
<div className="input-field col s12 vert-align">
<input
type="text"
id="cgroupName"
name="groupName"
value={groupName}
onChange={e => setGroupName(e.target.value)}
/>
<label htmlFor="cgroupName">Group Name</label>
</div>
</div>
<div className="row">
<div className="input-field col s12 vert-align">
<input
type="text"
id="cgroupModuleCode"
name="moduleCode"
value={moduleCode}
onChange={e => setModuleCode(e.target.value)}
/>
<label htmlFor="cgroupModuleCode">Module Code</label>
</div>
</div>
<div className="row">
<input
type="button"
value="Create Group"
onClick={() => createGroup(groupName, moduleCode)}
/>
</div>
<p id="groupCreateError">{errorMessage}</p>
</div>
</div>
</form>
</div>
<div class="row" id="groupDisplay">
{!!Object.keys(firebaseMock).length && (
<table id="groupDisplayTable">
<thead>
<tr id="groupDisplayTableHeader">
<th>Group Name</th>
<th>Module Code</th>
<th>Join Or View Group</th>
</tr>
</thead>
<tbody>
{Object.keys(firebaseMock).map(groupId => (
<tr>
<td>{groupId}</td>
<td>{firebaseMock[groupId].ModuleCode}</td>
<td class="groupDisplayTableButton">
<Button command={groupId} />
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
</div>
</div>
);
};
const Button = ({ command }) => {
const joinGroup = _command => console.log(_command);
return (
<button type="button" key={command} onClick={() => joinGroup(command)}>
Join Group
</button>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
这里唯一的区别是我的函数都不包含HTML,它们只是操纵状态。将来,思考的一种简单方法是始终确保HTML代码仅存在于render函数中。这样,其他所有内容都只能操纵数据和状态。应用程序(数据)的灵魂与应用程序(HTML)的主体之间的这种分离使HTML的“反应”变为状态的变化,这是框架的重点。