Я создаю приложение, которое может отображать проекты, в этом проекте есть несколько дочерних компонентов и серверных функций, работающих при создании пользователем нового проекта. Это приводит к изменению реквизита, что приводит к обновлению ProjectList, что нормально, но затем он также создает два представленных проекта, когда в базе данных он показывает один, а при обновлении - один.

Скриншот дублированной записи проекта

После обновления страницы

Как это работает после обновления, это заставляет меня думать, что это как-то связано с государством?

Итак, у меня есть компонент Dashboard -> Список проектов -> Детали списка проектов

Код приборной панели

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;

Компонент CreateProject

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 });
      });
    //
  };
};

ProjectReducer

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
      });
  });
0
Alex Hyslop 10 Дек 2019 в 13:28

1 ответ

Ваш компонент ProjectList содержит предыдущее состояние внутри него. Когда вы добавляете новый Project, пожарный магазин предоставляет вам список проектов, но я думаю, что вы отображаете проекты, используя метод array.push в компоненте ProjectList. Можете ли вы поделиться компонентом ProjectList?

0
warmachine 10 Дек 2019 в 13:51
Спасибо за ответ, я добавил другие компоненты.
 – 
Alex Hyslop
10 Дек 2019 в 13:58
Сколько массивов вы получаете внутри метода рендеринга компонента ProjectListDetails при добавлении нового проекта ??
 – 
warmachine
10 Дек 2019 в 14:14
Он отображает все проекты из моей базы данных firebase, а затем фильтрует их, если они принадлежат организации. Затем они помещаются в компонент ProjectListDetails. Похоже, он повторно рендерится несколько раз, не приведет ли это к случайному отображению нескольких элементов одного компонента?
 – 
Alex Hyslop
10 Дек 2019 в 14:35
У меня также есть функция на стороне сервера firebase, которая складывает все проекты + комментарии, чтобы я мог показывать проекты с большим количеством проектов + комментариев вверху.
 – 
Alex Hyslop
10 Дек 2019 в 14:38
Можете ли вы добавить в сообщение компонент CreateProject? чтобы я мог лучше понять, почему это происходит?
 – 
warmachine
10 Дек 2019 в 15:04