React组件中的重复次数很多

时间:2017-12-07 22:57:22

标签: reactjs structure

我有一个相当大的React组件,用于管理我网站上作业的详细信息显示。

我想做一些更聪明的事情

  1. 该组件有几个用于打开对话框的选项。对于每个对话框,我有一个单独的打开和关闭功能。例如handleImageGridShowhandleImageGridClose。有什么方法可以更简洁吗?
  2. 我有许多演示组件(例如ViewJobDetails),其中显示了有关作业的详细信息。我的问题是我必须将它们作为道具传递给每个组件,并且我一遍又一遍地传递相同的道具
  3. 当我从firebase加载数据时,我经常需要进行类似的检查,以便在呈现组件(e.g.this.state.selectedImageGrid && <ImageGridDialog />)之前查看数据是否存在。有没有更巧妙的方法来解决这个问题?

    从'react'导入React,{Component};

    import { withStyles } from 'material-ui/styles';
    import ViewJobAttachment from "../../components/jobs/viewJobAttachment";
    import ViewJobDetails from "../../components/jobs/viewJob/viewJobDetails";
    import ViewJobActions from "../../components/jobs/viewJob/viewJobActions";
    import ViewCompanyDetails from "../../components/jobs/viewJob/viewCompanyDetails";
    import ViewClientsDetails from "../../components/jobs/viewJob/viewClientsDetails";
    import ViewProductsDetails from "../../components/jobs/viewJob/viewProductsDetails";
    import ViewAttachmentDetails from "../../components/jobs/viewJob/viewAttachmentDetails";
    import ViewEventLogDetails from "../../components/jobs/viewJob/viewEventLogDetails";
    import ViewSummaryDetails from "../../components/jobs/viewJob/viewSummary";
    import {FirebaseList} from "../../utils/firebase/firebaseList";
    import SimpleSnackbar from "../../components/shared/snackbar";
    import {calculateTotalPerProduct} from "../../utils/jobsService";
    import BasicDialog from "../../components/shared/dialog";
    import ImageGrid from "../../components/shared/imageGrid";
    import Spinner from "../../components/shared/spinner";
    import ViewPinnedImageDialog from "../../components/jobs/viewEntry/viewPinnedImage";
    import {
      Redirect
    } from 'react-router-dom';
    
    const styles = theme => ({
      wrapper: {
        marginBottom: theme.spacing.unit*2
      },
      rightElement: {
        float: 'right'
      }
    });
    
    const ImageGridDialog = (props) => {
      return (
        <BasicDialog open={!!props.selectedImageGrid}
                     handleRequestClose={props.handleRequestClose}
                     fullScreen={props.fullScreen}
                     title={props.title}
        >
          <ImageGrid selectedUploads={props.selectedImageGrid}
                         handleClickOpen={props.handleClickOpen}/>
        </BasicDialog>
      )
    };
    
    class ViewJob extends Component {
      constructor() {
        super();
    
        this.state = {
          currentJob: null,
          entries: [],
          promiseResolved: false,
          attachmentDialogOpen: false,
          openAttachment: null,
          selectedImageGrid: false,
          selectedPinnedImage: false,
          showSnackbar: false,
          snackbarMsg: '',
          markedImageLoaded: false,
          loading: true,
          redirect: false
        };
    
        this.firebase = new FirebaseList('jobs');
    
        this.handleJobStatusChange = this.handleJobStatusChange.bind(this);
        this.handleImageGridShow = this.handleImageGridShow.bind(this);
        this.handleImageGridClose = this.handleImageGridClose.bind(this);
        this.handlePinnedImageClose = this.handlePinnedImageClose.bind(this);
        this.handlePinnedImageShow = this.handlePinnedImageShow.bind(this);
        this.handleMarkedImageLoaded = this.handleMarkedImageLoaded.bind(this);
        this.handleRemove = this.handleRemove.bind(this);
        this.pushLiveToClient = this.pushLiveToClient.bind(this);
      }
    
      componentDidMount() {
        this.firebase.db().ref(`jobs/${this.props.id}`).on('value', (snap) => {
          const job = {
            id: snap.key,
            ...snap.val()
          };
          this.setState({
            currentJob: job,
            loading: false
          })
        });
    
        const previousEntries = this.state.entries;
    
        this.firebase.db().ref(`entries/${this.props.id}`).on('child_added', snap => {
          previousEntries.push({
            id: snap.key,
            ...snap.val()
          });
    
          this.setState({
            entries: previousEntries
          })
        });
      }
    
      handleRemove() {
        this.firebase.remove(this.props.id)
          .then(() => {
            this.setState({redirect: true})
          })
      };
    
      pushLiveToClient() {
        const updatedJob = {
          ...this.state.currentJob,
          'lastPushedToClient': Date.now()
        };
        this.firebase.update(this.state.currentJob.id, updatedJob)
          .then(() => this.handleSnackbarShow("Job pushed live to client"))
      }
    
      handleJobStatusChange() {
        const newState = !this.state.currentJob.completed;
        const updatedJob = {
          ...this.state.currentJob,
          'completed': newState
        };
        this.firebase.update(this.state.currentJob.id, updatedJob)
      }
    
      handleSnackbarShow = (msg) => {
        this.setState({
          showSnackbar: true,
          snackbarMsg: msg
        });
      };
    
      handleSnackbarClose= (event, reason) => {
        if (reason === 'clickaway') {
          return;
        }
        this.setState({ showSnackbar: false });
      };
    
      handleAttachmentDialogClose =() => {
        this.setState({attachmentDialogOpen: false})
      };
    
      handleClickOpen = (file) => {
        this.setState({
          attachmentDialogOpen: true,
          openAttachment: file
        });
      };
    
      handleImageGridShow(imageGrid) {
        this.setState({selectedImageGrid: imageGrid})
      }
    
      handleImageGridClose() {
        this.setState({selectedImageGrid: false})
      }
    
      handlePinnedImageShow(pinnedImage) {
        this.setState({selectedPinnedImage: pinnedImage})
      }
    
      handlePinnedImageClose() {
        this.setState({selectedPinnedImage: false})
      }
    
      handleMarkedImageLoaded() {
        this.setState({markedImageLoaded: true})
      }
    
      render() {
        const {classes} = this.props;
        let {_, costPerItem} = calculateTotalPerProduct(this.state.entries);
        if (this.state.redirect) {
          return <Redirect to='/jobs' push/>
        } else {
          if (this.state.loading) {
            return <Spinner/>
          } else {
            return (
              <div className={styles.wrapper}>
                {this.state.currentJob &&
                <div>
                  <ViewJobActions currentJob={this.state.currentJob}
                                  handleJobStatusChange={this.handleJobStatusChange}
                                  pushLiveToClient={this.pushLiveToClient}
                  />
                  <ViewJobDetails currentJob={this.state.currentJob}/>
                  <ViewCompanyDetails currentJob={this.state.currentJob}/>
                  <ViewClientsDetails currentJob={this.state.currentJob}/>
                  <ViewProductsDetails currentJob={this.state.currentJob}/>
                  {this.state.currentJob.selectedUploads && this.state.currentJob.selectedUploads.length > 0
                    ? <ViewAttachmentDetails currentJob={this.state.currentJob} handleClickOpen={this.handleClickOpen}/>
                    : null}
                  <ViewEventLogDetails jobId={this.state.currentJob.jobId}
                                       jobKey={this.state.currentJob.id}
                                       entries={this.state.entries}
                                       handlePinnedImageShow={this.handlePinnedImageShow}
                                       handleImageGridShow={this.handleImageGridShow}/>
                  <ViewSummaryDetails stats={costPerItem}/>
                  <ViewJobAttachment open={this.state.attachmentDialogOpen}
                                     handleRequestClose={this.handleAttachmentDialogClose}
                                     attachment={this.state.openAttachment}
                  />
                  {this.state.selectedImageGrid &&
                  <ImageGridDialog selectedImageGrid={this.state.selectedImageGrid}
                                   handleRequestClose={this.handleImageGridClose}
                                   handleClickOpen={this.handleClickOpen}
                                   title="Pictures for job"
                                   fullScreen={false}/>}
                  {this.state.selectedPinnedImage &&
                  <ViewPinnedImageDialog attachment={this.state.selectedPinnedImage}
                                         open={!!this.state.selectedPinnedImage}
                                         markedImageLoaded={this.state.markedImageLoaded}
                                         handleMarkedImageLoaded={this.handleMarkedImageLoaded}
                                         handleRequestClose={this.handlePinnedImageClose}
                                         otherMarkedEntries={this.state.entries}
                  />
                  }
                  <SimpleSnackbar showSnackbar={this.state.showSnackbar}
                                  handleSnackbarClose={this.handleSnackbarClose}
                                  snackbarMsg={this.state.snackbarMsg}/>
    
                </div>}
              </div>
            );
          }
        }
      }
    }
    
    export default withStyles(styles)(ViewJob);
    

1 个答案:

答案 0 :(得分:0)

您可以定义一个常规组件方法并将其绑定在像onSomething={this.handler.bind(this, index)}这样的处理程序中,假设您在索引var中有一些可区别的东西

功能应该如下所示

handler(index) {
  ...
}