【发布时间】:2019-12-10 10:28:16
【问题描述】:
我正在创建一个可以显示项目的应用程序,当用户创建新项目时,该项目有一些子组件和服务器端功能正在运行。这会导致道具发生变化,从而导致 ProjectList 刷新,这很好,但是当它在数据库中显示一个时,它也会生成两个提交的项目,而当您刷新它时,它会显示一个。
Screenshot of duplicated project entry
因为它在刷新后工作,它让我觉得它与状态有关?
所以我有一个仪表板组件 -> 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