【问题标题】:Component Elements Re render & duplicate, but fix on refresh组件元素重新渲染和复制,但修复刷新
【发布时间】:2019-12-10 10:28:16
【问题描述】:

我正在创建一个可以显示项目的应用程序,当用户创建新项目时,该项目有一些子组件和服务器端功能正在运行。这会导致道具发生变化,从而导致 ProjectList 刷新,这很好,但是当它在数据库中显示一个时,它也会生成两个提交的项目,而当您刷新它时,它会显示一个。

Screenshot of duplicated project entry

After page refresh

因为它在刷新后工作,它让我觉得它与状态有关?

所以我有一个仪表板组件 -> ProjectList -> ProjectListDetails

仪表板代码

import React, { Component } from "react";
import { connect } from "react-redux";
import { firestoreConnect } from "react-redux-firebase";
import ProjectList from "../Projects/ProjectList";
import { compose } from "redux";
import CreateProject from "../Projects/CreateProject";
import { Redirect } from "react-router-dom";

class Dashboard extends Component {
  render() {
    const { projects, auth, profile, organisations } = this.props;
    if (!auth.uid) return <Redirect to="/signin" />;
    //is the logged in user an Organisation or Single account?
    const isOrg =
      profile.isOrg === true ? (
        <p>Organisation Account</p>
      ) : (
        <p>Single Account</p>
      );

    return (
      <div className="container">
        <div className="row home-header-row">
          <div className="col-md-12 section text-center">
            {isOrg}
            <br></br>

            <CreateProject organisations={organisations} />
            <ProjectList
              projects={projects}
              authID={auth.uid}
              profile={profile}
            />
          </div>
        </div>
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    projects: state.firestore.ordered.projects,
    auth: state.firebase.auth,
    profile: state.firebase.profile,
    notifications: state.firestore.ordered.notifications,
    organisations: state.firestore.ordered.organisations
  };
};

export default compose(
  connect(mapStateToProps),
  firestoreConnect([
    { collection: "projects", orderBy: ["totalEntries", "desc"] },
    { collection: "organisations", orderBy: ["time", "desc"] },
    { collection: "notifications", limit: 5, orderBy: ["time", "desc"] }
  ])
)(Dashboard);

项目列表组件:

import React, { Component } from "react";
import ProjectListDetails from "./ProjectListDetails";

import "firebase/firestore";

class ProjectList extends Component {
  // shouldComponentUpdate(nextProps, nextState) {
  //     return this.props.projects !== nextProps.projects;
  //   }

  render() {
    return (
      <div className="project-list section">
        {this.props.projects &&
          this.props.projects.map(project => {
            const projectId =
              project.authorID +
              project.createdAt.toDate().toLocaleTimeString("it-it") +
              project.title;

            return (
              <>
                {project.canView.includes(this.props.profile.email) ||
                project.authorEmail.includes(this.props.profile.email) ? (
                  <ProjectListDetails
                    project={project}
                    profile={this.props.profile}
                    projectId={projectId}
                  ></ProjectListDetails>
                ) : null}
              </>
            );
          })}
      </div>
    );
  }
}

export default ProjectList;

ProjectListDetails 组件

import React, { Component } from "react";

import EditProject from "./EditProjects";
import DeleteProject from "./DeleteProject";
import { Link } from "react-router-dom";
import ProjectSummary from "./ProjectSummary";

class ProjectListDetails extends Component {
  render() {
    console.log("printing project : " + this.props.project.title);

    return (
      <div className="row" key={this.props.project.id}>
        <div className="col-md-12" key={this.props.project.projectID}>
          <button
            className="btn btn-secondary dropdown-toggle project-options"
            type="button"
            id="dropdownMenuButton"
            data-toggle="dropdown"
            aria-haspopup="true"
            aria-expanded="false"
          >
            Options
          </button>
          <div
            className="dropdown-menu"
            aria-labelledby="dropdownMenuButton"
            id={this.props.project.projectID}
          >
            <EditProject />
            <DeleteProject />
          </div>

          <Link
            to={"/project/" + this.props.project.id}
            key={this.props.project.id}
            profile={this.props.profile}
            projectId={this.props.projectId}
          >
            <ProjectSummary
              projectId={this.props.projectId}
              project={this.props.project}
              key={this.props.project.id}
              authID={this.props.authID}
            />
          </Link>
        </div>
      </div>
    );
  }
}

export default ProjectListDetails;

创建项目组件

import React, { Component } from "react";
import { connect } from "react-redux";
import { createProject } from "../../Store/Actions/projectActions";
import Button from "react-bootstrap/Button";
import Modal from "react-bootstrap/Modal";

// import ReactQuill from 'react-quill'
// import 'react-quill/dist/quill.snow.css'
// import renderHTML from 'react-render-html';

class CreateProject extends Component {
  state = {
    title: "",
    content: "",
    projectAmount: 0,
    commentAmount: 0,
    hideModal: false,
    showModal: "",
    show: false,
    setShow: false,
    canView: [],
    organisation: ""
  };

  handleChange = e => {
    this.setState({
      [e.target.id]: e.target.value
    });
  };

  handleSubmit = e => {
    e.preventDefault();

    this.setState({ canView: [] });

    this.props.organisations &&
      this.props.organisations.map(organisation => {
        if (organisation.canView.includes(this.props.profile.email)) {
          const orgUser = organisation.canView.map((item, key) =>
            this.state.canView.push(item)
          );
          return orgUser;
        }
        return null;
      });
    this.props.createProject(this.state);

    document.getElementById("title").value = "";
    document.getElementById("content").value = "";
  };

  handleClose = () => {
    this.setState({
      show: false
    });
  };
  handleShow = () => {
    this.setState({
      show: true
    });
  };

  render() {
    return (
      <>
        <Button
          className="btn btn-primary"
          variant="primary"
          onClick={this.handleShow}
        >
          New Project
        </Button>

        <Modal show={this.state.show} onHide={this.handleClose}>
          <Modal.Header closeButton>
            <Modal.Title>New Project</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <form onSubmit={this.handleSubmit}>
              <div className="form-group">
                <input
                  onChange={this.handleChange}
                  className="form-control"
                  type="text"
                  id="title"
                  placeholder="Project Title"
                />
              </div>
              <div className="form-group">
                <textarea
                  onChange={this.handleChange}
                  className="form-control"
                  id="content"
                  rows="3"
                  placeholder="Project Content (can add some more options here later)"
                ></textarea>
              </div>
              <Modal.Footer>
                <Button variant="secondary" onClick={this.handleClose}>
                  Close
                </Button>
                <Button
                  type="submit"
                  variant="primary"
                  onClick={this.handleClose}
                >
                  Save Changes
                </Button>
              </Modal.Footer>
            </form>
          </Modal.Body>
        </Modal>
      </>
    );
  }
}

const mapStateToProps = state => {
  return {
    projects: state.firestore.ordered.projects,
    auth: state.firebase.auth,
    profile: state.firebase.profile,
    organisations: state.firestore.ordered.organisations
  };
};

const mapDispatchToProps = dispatch => {
  return {
    createProject: project => dispatch(createProject(project))
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(CreateProject);

项目行动

export const createProject = project => {
  return (dispatch, getState, { getFirebase, getFirestore }) => {
    // make async call to database
    const firestore = getFirestore();
    const profile = getState().firebase.profile;
    const authorId = getState().firebase.auth.uid;
    const createdAt = new Date();
    const convertedDate = createdAt.toLocaleTimeString("it-it");
    const printFirstName =
      profile.isOrg === true ? profile.orgFirstName : profile.firstName;
    const printLastName =
      profile.isOrg === true ? profile.orgLastName : profile.lastName;
    const projectId = authorId + convertedDate + project.title;
    const orgName = profile.organisation ? profile.organisation : "";

    //this.state.project.createdAt.toDate().toLocaleTimeString('it-it') + this.state.project.title

    firestore
      .collection("projects")
      .doc(projectId)
      .set({
        ...project,
        authorFirstName: printFirstName,
        authorLastname: printLastName,
        authorID: authorId,
        authorEmail: profile.email,
        canView: project.canView,
        canEdit: [profile.email],
        createdAt: createdAt,
        projectID: projectId,
        organisation: orgName,
        permalink: "/project/" + projectId
      })
      .then(() => {
        dispatch({ type: "CREATE_PROJECT", project });
      })
      .catch(err => {
        dispatch({ type: "CREATE_PROJECT_ERROR", err });
      });
    //
  };
};

项目减速器

const initState = {};

const projectReducer = (state = initState, action) => {
  switch (action.type) {
    case "CREATE_PROJECT":
      return state;
    case "DELETE_PROJECT":
      console.log("Project Deleted", action.project);
      return state;
    case "CREATE_PROJECT_ERROR":
      console.log("Create project error", action.err);
      return state;
    case "DELETE_PROJECT_ERROR":
      console.log("Delete project error", action.err);
      return state;
    default:
      return state;
  }
};

export default projectReducer;

Firebase 功能

exports.projectInnerEntries = functions.firestore
  .document("projects/{projectId}")
  .onWrite((change, context) => {
    const newValue = change.after.data();
    var projectAmount = newValue.projectAmount;
    var commentAmount = newValue.commentAmount;
    // var totalEntries = projectAmount + commentAmount;
    const notification = {
      projects: projectAmount,
      comments: commentAmount,
      total: projectAmount + commentAmount
    };

    return admin
      .firestore()
      .collection("projects")
      .doc(newValue.projectID)
      .update({
        totalEntries: notification.total
      });
  });

【问题讨论】:

    标签: reactjs firebase redux react-redux


    【解决方案1】:

    您的 ProjectList 组件在其中保持以前的状态,当您添加新项目时,firestore 会为您提供项目列表,但我认为您正在使用 ProjectList 组件中的 array.push 方法显示项目。你能分享项目列表组件?

    【讨论】:

    • 感谢您的回复,我现在添加了其他组件。
    • 在添加新项目时,您在 ProjectListDetails 组件的 render 方法中获取了多少个数组??
    • 它映射出我的 firebase 数据库中的所有项目,然后如果它们在组织中,则对其进行过滤。然后将它们放入 ProjectListDetails 组件中。它看起来像是多次重新渲染,这会导致它意外显示一个组件的多个元素吗?
    • 我还有一个 firebase 服务器端功能,它将项目总数 + cmets 加在一起,因此我可以在顶部显示项目数量较多的项目 + cmets。
    • 您可以将 CreateProject 组件添加到帖子中吗?这样我就可以更多地了解它为什么会发生?
    猜你喜欢
    • 1970-01-01
    • 2022-11-21
    • 1970-01-01
    • 2020-02-13
    • 1970-01-01
    • 2022-01-19
    • 2022-12-19
    • 2016-10-18
    • 1970-01-01
    相关资源
    最近更新 更多