父组件更改时,构造函数不会在子组件中每次都调用

时间:2019-05-27 06:29:38

标签: reactjs next.js

当父组件发生更改时,构造函数不会在子组件中每次都调用。在父级组件中,有一个Developer下拉过滤器。当我们更改开发者下拉菜单时,开发者任务会以开发者任务组件的形式显示。并且我在Developertask组件中添加了另一个Timer组件以显示任务计时器。

timetracker.js

import React, { Component, Fragment } from "react";

import App from "../components/App";
import Header from "../components/Header";
import TodoInlineForm from "../components/TodoInlineForm";

import DeveloperTasks from "../components/DeveloperTasks";
import Typography from "@material-ui/core/Typography";
import FormControl from "@material-ui/core/FormControl";
import InputLabel from "@material-ui/core/InputLabel";
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";
import { withStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import IconButton from "@material-ui/core/IconButton";
import MuiDialogTitle from "@material-ui/core/DialogTitle";
import MuiDialogContent from "@material-ui/core/DialogContent";

import CloseIcon from "@material-ui/icons/Close";

const styles = theme => ({
  toolbar: theme.mixins.toolbar,
  content: {
    flexGrow: 1
  },

});

const DialogTitle = withStyles(theme => ({
  root: {
    borderBottom: `1px solid ${theme.palette.divider}`,
    margin: 0,
    padding: theme.spacing.unit * 2
  },
  closeButton: {
    position: "absolute",
    right: theme.spacing.unit,
    top: theme.spacing.unit,
    color: theme.palette.grey[500]
  }
}))(props => {
  const { children, classes, onClose } = props;
  return (
    <MuiDialogTitle disableTypography className={classes.root}>
      <Typography variant="h6">{children}</Typography>
      {onClose ? (
        <IconButton
          aria-label="Close"
          className={classes.closeButton}
          onClick={onClose}
        >
          <CloseIcon />
        </IconButton>
      ) : null}
    </MuiDialogTitle>
  );
});
class TimeTracker extends React.Component {
  state = {
    developer: "",
    open: false,
    fullWidth: true,
    maxWidth: "md",
    taskid: ""
  };

  handleChange = name => event => {
    this.setState({ open: false });
    this.setState({ [name]: event.target.value });
  };


  handleClose = () => {
    this.setState({ open: false });
  };

  render() {
    const { classes, theme } = this.props;
    let developerlist;
    let todoinlineform;
    if (
      typeof this.state.developer != "undefined" &&
      this.state.developer != ""
    ) {
      developerlist = (
        <DeveloperTasks contact_id={this.state.developer} open={false} />
      );
    }

    if (this.state.open && this.state.open === true) {
      todoinlineform = (
        <TodoInlineForm
          open={this.state.open}
          modaltitle="Add Todo"
          onClose={this.handleClose}
        />
      );
    }

    return (
      <App>
        <Header />
        <main className={classes.content}>
          <div className={classes.toolbar} />
          <div className={classes.paper}>
            <form autoComplete="off">
              <FormControl className={classes.formControl}>
                <InputLabel htmlFor="developer">Select Developer</InputLabel>
                <Select
                  fullWidth
                  value={this.state.developer}
                  onChange={this.handleChange("developer")}
                  inputProps={{
                    name: "developer",
                    id: "developer"
                  }}
                >
                  <MenuItem value="">
                    <em>Please Select Developer</em>
                  </MenuItem>
                  <MenuItem
                    key="rigal"
                    value="b62b9815-b1c7-dc4a-7539-59a68b95ddf5"
                  >
                    Rigal Patel
                  </MenuItem>
                  <MenuItem
                    key="ankit"
                    value="1e1eafa8-ea40-6f43-6541-5c7f539612f2"
                  >
                    Ankit Patel
                  </MenuItem>
                </Select>
              </FormControl>
              <Button
                variant="contained"
                color="Primary"
                className={classes.button}
                onClick={this.handleOpen()}
              >
                Add New Task
              </Button>
              {todoinlineform}
              {developerlist}
            </form>
          </div>
        </main>
      </App>
    );
  }
}
export default withStyles(styles, { withTheme: true })(TimeTracker);

上面的代码仅显示在Developer下拉列表中,当下拉列表更改时,我添加了条件的Developertask组件。

DeveloperTasks.js

import { Mutation, Query } from "react-apollo";
import gql from "graphql-tag";
import React, { Component, Fragment } from "react";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";

import TaskTimer from "./TaskTimer";
import Note from "./Note";
import getCDTime from "../util/commonfunc";

import Button from "@material-ui/core/Button";
import IconButton from "@material-ui/core/IconButton";
import Paper from "@material-ui/core/Paper";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
import CircularProgress from "@material-ui/core/CircularProgress";
import Avatar from "@material-ui/core/Avatar";
import FormControl from "@material-ui/core/FormControl";
import InputLabel from "@material-ui/core/InputLabel";
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";
import TextField from "@material-ui/core/TextField";
import Dialog from "@material-ui/core/Dialog";
import MuiDialogTitle from "@material-ui/core/DialogTitle";
import MuiDialogContent from "@material-ui/core/DialogContent";
import MuiDialogActions from "@material-ui/core/DialogActions";

import DeleteIcon from "@material-ui/icons/Delete";
import AssignmentIcon from "@material-ui/icons/Assignment";
import NotesIcon from "@material-ui/icons/EventNote";
import AssignmentInd from "@material-ui/icons/AssignmentInd";
import CheckCircleOutline from "@material-ui/icons/CheckCircleOutline";
import CheckCircle from "@material-ui/icons/CheckCircle";
import CloseIcon from "@material-ui/icons/Close";
import Typography from "@material-ui/core/Typography";
import EditIcon from "@material-ui/icons/Edit";
import notify from "../util/notify";

import DateFnsUtils from "@date-io/date-fns";
import {
  MuiPickersUtilsProvider,
  TimePicker,
  DatePicker
} from "material-ui-pickers";
import UserList from "../components/UserList";
import emails from "../components/UserList";
import TodoInlineForm from "../components/TodoInlineForm";
import UserListing from "../components/UserListing";

const ms = require("pretty-ms");



const styles = theme => ({
  root: {
    width: "100%",
    marginTop: theme.spacing(3),
    overflowX: "auto"
  },
});

const DialogTitle = withStyles(theme => ({
  root: {
    borderBottom: `1px solid ${theme.palette.divider}`,
    margin: 0,
    padding: theme.spacing.unit * 2
  },
  closeButton: {
    position: "absolute",
    right: theme.spacing.unit,
    top: theme.spacing.unit,
    color: theme.palette.grey[500]
  }
}))(props => {
  const { children, classes, onClose } = props;
  return (
    <MuiDialogTitle disableTypography className={classes.root}>
      <Typography variant="h6">{children}</Typography>
      {onClose ? (
        <IconButton
          aria-label="Close"
          className={classes.closeButton}
          onClick={onClose}
        >
          <CloseIcon />
        </IconButton>
      ) : null}
    </MuiDialogTitle>
  );
});

const DialogContent = withStyles(theme => ({
  root: {
    margin: 0,
    padding: theme.spacing.unit * 2
  }
}))(MuiDialogContent);

const DialogActions = withStyles(theme => ({
  root: {
    borderTop: `1px solid ${theme.palette.divider}`,
    margin: 0,
    padding: theme.spacing.unit
  }
}))(MuiDialogActions);

class DeveloperTasks extends React.Component {
  state = {
    start_date: new Date(),
    end_date: new Date(),
    status: "",
    task: "",
    searchTerm: "",
    open: false,
    openReAssign: false,
    openTodoForm: false,
    taskid: "",
    userTaskId: "",
    value: "",
    searchbydate: "",
    contact_id: "",
    openNotes: ""
  };
  constructor(props) {
    super(props);
    this.state = {
      start_date: new Date(),
      end_date: new Date(),
      contact_id: props.contact_id
    };
    this.searchUpdated = this.searchUpdated.bind(this);
  }
  handleDateChange = name => date => {
    this.setState({ [name]: date });
  };

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

  handleClickTodoOpen(taskid) {
    this.setState({ taskid: taskid, openTodoForm: true });
  }

  handleClickSearch = () => {
    this.setState({ searchbydate: "1" });
  };
  render() {
    let todoinlineform = "";
    let startdate = "";
    let enddate = "";
    const { classes, contact_id } = this.props;

    let currdatetime = getCDTime.getCurrentDateTime();

    let shownbutton = {
      display: "block"
    };
    if (
      this.state.openTodoForm &&
      this.state.openTodoForm === true &&
      this.state.taskid != ""
    ) {
      todoinlineform = (
        <TodoInlineForm
          open={this.state.openTodoForm}
          taskid={this.state.taskid}
          modaltitle="Edit Todo"
          onClose={this.closeTodoPopup}
        />
      );
    }

    if (this.state.searchbydate && this.state.searchbydate != "") {
      startdate = this.changeCustomDateFormat(this.state.start_date);
      enddate = this.changeCustomDateFormat(this.state.end_date);
    }

    return contact_id === "" ? (
      ""
    ) : (
      <Query
        query={tasksQuery}
        variables={{
          contact_id_c: contact_id,
          start_due_date: startdate,
          end_date: enddate
        }}
      >
        {({ loading, error, data: { Developertasklist } }) => {
          if (error) return <p>{error}</p>;
          if (loading) return <CircularProgress className={classes.progress} />;
          //Filter with task name
          if (this.state.task && this.state.task != "") {
            Developertasklist = Developertasklist.filter(
              developertasklist =>
                developertasklist.name
                  .toLowerCase()
                  .indexOf(this.state.task.toLowerCase()) != -1
            );
          }
          //Task status wise filter
          if (this.state.status && this.state.status != "") {
            Developertasklist = Developertasklist.filter(
              developertasklist => developertasklist.status == this.state.status
            );
          }

          //Label array for apply class on status label
          let labelcolor = [
            { status: "In Progress", class: classes.labelprogress },
            { status: "Completed", class: classes.labelcomplete },
            { status: "On Hold", class: classes.labelonhold },
            { status: "QA Fail", class: classes.labelqafail },
            { status: "Not Started", class: classes.labelnotstated },
            { status: "QA", class: classes.labelqa },
            { status: "QA Passed", class: classes.labelqapassed },
            { status: "Deferred", class: classes.labeldefered }
          ];
          return (
            <Fragment>
              <br />
              <div className={classes.tasklist}>
                <div className="picker">
                  <MuiPickersUtilsProvider utils={DateFnsUtils}>
                    <DatePicker
                      label="Start Date"
                      name="start_date"
                      value={this.state.start_date}
                      format="yyyy-MM-dd"
                      onChange={this.handleDateChange("start_date")}
                      className={classes.datepadding}
                      animateYearScrolling
                    />
                    <DatePicker
                      label="End Date"
                      name="end_date"
                      value={this.state.end_date}
                      format="yyyy-MM-dd"
                      onChange={this.handleDateChange("end_date")}
                      className={classes.datepadding}
                      animateYearScrolling
                    />
                  </MuiPickersUtilsProvider>
                  <Button
                    type="button"
                    variant="contained"
                    color="primary"
                    className={classes.button}
                    onClick={event => {
                      this.handleClickSearch();
                    }}
                  >
                    Search
                  </Button>
                  <Button
                    variant="contained"
                    color="secondary"
                    className={classes.button}
                    onClick={event => {
                      this.handleClickReset();
                    }}
                  >
                    Reset
                  </Button>
                </div>
                <FormControl className={classes.formControl}>
                  <InputLabel htmlFor="status-simple">Status</InputLabel>
                  <Select
                    value={this.state.status}
                    onChange={this.handleChange("status")}
                    className={classes.elementpadding}
                    inputProps={{
                      name: "status",
                      id: "status"
                    }}
                  >
                    <MenuItem value="">
                      <em>Please Select</em>
                    </MenuItem>
                    <MenuItem value="Not Started">Not Started</MenuItem>
                    <MenuItem value="In Progress">In Progress</MenuItem>
                    <MenuItem value="On Hold">On Hold</MenuItem>
                    <MenuItem value="Deferred">Deferred</MenuItem>
                    <MenuItem value="Completed">Completed</MenuItem>
                    <MenuItem value="QA">QA</MenuItem>
                    <MenuItem value="QA Passed">QA Passed</MenuItem>
                    <MenuItem value="QA Fail">QA Fail</MenuItem>
                  </Select>
                </FormControl>
                &nbsp;
                <TextField
                  id="standard-name"
                  label="Task"
                  className={classes.textField}
                  value={this.state.task}
                  onChange={this.handleChange("task")}
                />
              </div>

              <div className={classes.tasklist}>
                <Paper className={classes.listroot}>
                  <List className={classes.listroot}>
                    {Developertasklist.map((task, index) => {
                      let statusLabel = labelcolor.filter(
                        obj => obj.status == task.status
                      );
                      let completeStatusClass = classes.hideelement;
                      let pendingStatusClass = "";
                      let hidetimer = "";

                      if (task.status === "Completed") {
                        pendingStatusClass = classes.hideelement;
                        hidetimer = "hide";
                        completeStatusClass = "";
                      }
                      if (statusLabel.length > 0)
                        statusLabel = statusLabel[0].class;

                      let currentdatetime = new Date(task.due_date);
                      let start_time = new Date(task.start_due_date);
                      let time_diff = Math.abs(currentdatetime - start_time) / 1000;

                      return (
                        <ListItem key={index} divider="true">
                          <div className={classes.taskwidth}>
                            <Avatar>
                              <AssignmentIcon />
                            </Avatar>
                            <ListItemText
                              primary={
                                <React.Fragment>
                                  {task.name} - {task.due_date}
                                </React.Fragment>
                              }
                              secondary={
                                <React.Fragment>
                                  <Typography
                                    component="span"
                                    className={[classes.label, statusLabel]}
                                    color="textPrimary"
                                  >
                                    {task.status}
                                  </Typography>
                                  <Typography variant="caption" gutterBottom  className={[classes.etime]}>
                                      Estimated Hours:  {  time_diff / 3600 } Hours
                                  </Typography>
                                </React.Fragment>
                              }
                            />
                          </div>
                          <div className={classes.timerwidth}>
                            <div>
                              <TaskTimer
                                developerlist={task}
                                hidetimer={hidetimer}
                                alltasklist={Developertasklist}
                                //hidetimer={this.state.disabledList[n]}
                                //disableOtherTimersCallback={getDisableOtherTimersCallback()}
                              />
                            </div>
                          </div>
                          <div className={classes.width5}>
                            <EditIcon
                              className={classes.icon}
                              onClick={event => {
                                this.handleClickTodoOpen(task.id);
                              }}
                            />
                          </div>
                          <div className={classes.width5}>
                            <Mutation mutation={COMPLETE_TASK_OPERATIONS}>
                              {(todo_operations, { loading, error }) => (
                                <CheckCircleOutline
                                  className={[pendingStatusClass, classes.icon]}
                                  onClick={event => {
                                    let confirmcomplete = window.confirm(
                                      "Are you sure you want to complete this Task?"
                                    );
                                    confirmcomplete &&
                                      todo_operations({
                                        variables: {
                                          id: task.id,
                                          actual_due_date: currdatetime,
                                          status: "Completed"
                                        }
                                      }) &&
                                      notify.notify(
                                        "success",
                                        "Task Completed successfully!"
                                      );
                                  }}
                                />
                              )}
                            </Mutation>
                            <CheckCircle
                              className={[
                                classes.icon,
                                classes.completeIcon,
                                completeStatusClass
                              ]}
                            />
                          </div>
                          <div className={classes.width5}>
                            <div className={pendingStatusClass}>
                              <AssignmentInd
                                className={classes.icon}
                                onClick={event => {
                                  this.handleClickDialogOpen(task.id);
                                }}
                              />
                              <UserListing
                                classes={{
                                  paper: classes.userlistingstyle
                                }}
                                //open={this.state.openReAssign}
                                open={this.state.userTaskId === task.id}
                                onClose={this.handleDialogClose}
                                //value={this.state.value}
                                value={task.contact_id_c}
                                userTaskId={this.state.userTaskId}
                              />
                            </div>
                          </div>
                          <div className={classes.width5}>
                            <NotesIcon
                              className={classes.icon}
                              onClick={this.handleClickOpen(task.id)}
                            />
                            <Dialog
                              onClose={this.handleClose}
                              aria-labelledby="customized-dialog-title"
                              open={this.state.openNotes === task.id}
                            >
                              <DialogTitle
                                id="customized-dialog-title"
                                onClose={this.handleClose}
                              >
                                Notes
                              </DialogTitle>
                              <DialogContent>
                                <Note
                                  todoid={task.id}
                                  closeNote={this.handleClose}
                                />
                              </DialogContent>
                            </Dialog>
                          </div>
                          <div className={classes.width5}>
                            <Mutation mutation={DELETE_TODO}>
                              {(todo_operations, { loading, error }) => (
                                <DeleteIcon
                                  className={classes.icon}
                                  aria-label="Delete"
                                  onClick={event => {
                                    let confirmdelete = window.confirm(
                                      "Are you sure you want to delete this Task?"
                                    );
                                    confirmdelete &&
                                      todo_operations({
                                        variables: {
                                          id: task.id,
                                          deleted: "1"
                                        }
                                      }) &&
                                      notify.notify(
                                        "success",
                                        "Record deleted successfully!"
                                      );
                                  }}
                                />
                              )}
                            </Mutation>
                          </div>
                        </ListItem>
                      );
                    })}
                  </List>
                </Paper>
              </div>
              {todoinlineform}
            </Fragment>
          );
        }}
      </Query>
    );
  }
}

export default withStyles(styles, { withTheme: true })(DeveloperTasks);

The above components are display developer tasks based on developer dropdown value. I have added Timer Component for task time tracking.

I have passed the task object in the Timer component and get task object value in timer components as Props but not getting props value in the constructor because when we change developer Dropdown in starting (two-three timer construct call so I get task object in props but after that constructor not call (seems like data get form cache).

    ```
    import { Mutation, Query } from "react-apollo";
    import gql from "graphql-tag";
    const React = require("react");
    const ms = require("pretty-ms");
    import PropTypes from "prop-types";
    import { withStyles } from "@material-ui/core/styles";
    import StartIcon from "@material-ui/icons/PlayCircleFilled";
    import StopIcon from "@material-ui/icons/Stop";
    import getCDTime from "../util/commonfunc";
    enter code here
    const styles = theme => ({
      button: {
        margin: theme.spacing.unit
      },
    });

    class TaskTimer extends React.Component {
      constructor(props) {
        const total_time = !props.developerlist.dtask_total_time
          ? parseInt(0)
          : parseInt(props.developerlist.dtask_total_time);

        let statetime = total_time;
        let stateison = false;
        super(props);

        if (props.developerlist.time_tracking_flag === "yes") {
          let currentdatetime = new Date(getCDTime.getCurrentDateTime());
          let start_time = new Date(props.developerlist.dtask_start_time);
          let time_diff = Math.abs(currentdatetime - start_time) / 1000;

          statetime = time_diff + total_time;

          stateison = true;
          this.state = {
            time: statetime,
            isOn: stateison
          };
          this.startTimer();
        }
        this.state = {
          time: statetime,
          isOn: stateison
        };

        this.startTimer = this.startTimer.bind(this);
        this.stopTimer = this.stopTimer.bind(this);
      }

      startTimer(next) {
        this.setState({
          isOn: true,
          time: this.state.time
        });

        this.timer = setInterval(
          () =>
            this.setState({
              time: parseInt(this.state.time + 1)
            }),
          1000
        );
      }
      stopTimer() {
        this.state.time = parseInt(this.state.time);
        this.setState({ isOn: false });
        clearInterval(this.timer);
      }

      getDisableOtherTimersCallback() {
        alert("here");
      }

      render() {
        let totalTaskTime = parseInt(this.state.time) * 1000;

        const { classes, theme } = this.props;
        let currdatetime = getCDTime.getCurrentDateTime();
        let currentDate = new Date(currdatetime).toDateString();
        let taskStateDate = new Date(
          this.props.developerlist.dtask_start_time
        ).toDateString();
        let dailyhours =
          currentDate != taskStateDate
            ? this.props.developerlist.dtask_total_time
            : 0;

        return (
          <div>
            <div className={classes.clock}>{ms(totalTaskTime)}</div>
            {start}

            {stop}
          </div>
        );
      }
    }
    export default withStyles(styles, { withTheme: true })(TaskTimer);
    ```
Anyone, please suggest a possible solution to fix this issue.

0 个答案:

没有答案