使用React类创建多个按钮

时间:2019-12-04 13:59:56

标签: javascript html node.js reactjs firebase

我目前正在尝试使用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);

3 个答案:

答案 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的“反应”变为状态的变化,这是框架的重点。