在React中重构大型View组件

时间:2017-11-10 20:27:45

标签: html reactjs refactoring

我有一个相当大的视图组件来呈现一个表单,用户可以在其中添加注释,上传图像,在多个其他产品之间进行选择并提交。我将状态和功能保存在一个单独的组件中,并对该设置非常满意。

视图已大幅增长,我对应用程序的结构并不完全满意。

特别令我烦恼的是

  1. 我必须将相同的propsclasses变量传递给我使用的每个组件
  2. 我的主视图组件CreateEntryForm和每个较小的组件中都混合了逻辑
  3. 非常感谢有关如何更好地构建此代码的任何提示

    import React from 'react';
    import TextField from 'material-ui/TextField';
    import Button from 'material-ui/Button';
    import { MenuItem } from 'material-ui/Menu';
    import { withStyles } from 'material-ui/styles';
    import Chip from 'material-ui/Chip';
    import Typography from 'material-ui/Typography';
    import { CircularProgress } from 'material-ui/Progress';
    import EntryImageView from "./entryImageView";
    import {MarkedImage} from "./markedImage";
    
    
    const styles = theme => ({
      button: {
        margin: theme.spacing.unit,
      },
      container: {
        display: 'flex',
        flexWrap: 'wrap',
      },
      menu: {
        width: 200,
      },
      chipContainer: {
        marginTop: theme.spacing.unit * 2,
        display: 'flex',
        flexWrap: 'wrap',
      },
      chip: {
        margin: theme.spacing.unit / 2,
      },
      wrapper: {
        marginTop: theme.spacing.unit*2
      },
    });
    
    
    const ProductFormGroup = (props) => (
      <div>
        <TextField
          id="selectedProduct"
          required
          select
          label="Select a product"
          error={props.selectProductError !== ''}
          margin="normal"
          fullWidth
          value={(props.currentEntry.currentProduct === undefined || props.currentEntry.currentProduct === null) ? "" : props.currentEntry.currentProduct}
          onChange={props.handleInputChange('currentProduct')}
          SelectProps={{
            MenuProps: {
              className: props.menu,
            },
            name: "currentProduct"
          }}
          helperText={props.selectProductError || ""}
        >
          {props.job.selectedProducts.map((product, index) => (
            <MenuItem key={index} value={product}>
              {product.name}
            </MenuItem>
          ))}
        </TextField>
        <TextField
          margin="dense"
          id="productQuantity"
          label="Product Quantity"
          fullWidth
          name="productQuantity"
          onChange={props.handleInputChange('productQuantity')}
          value={props.productQuantity} />
        <Button color="primary"
                onClick={() => props.addSelectedChip()}
                disabled={(props.productQuantity === '' || props.currentEntry.currentProduct === null)}>
          add product
        </Button>
      </div>
    );
    
    const SelectedProductsGroup = (props) => (
      <div>
        <TextField
          id="currentUpload"
          select
          label="Select an image to mark"
          margin="normal"
          fullWidth
          value={props.currentUpload || ''}
          onChange={props.handleInputChange('currentUpload')}
          SelectProps={{
            MenuProps: {
              className: props.menu,
            },
            name: "currentUpload"
          }}
        >
          {props.job.selectedUploads.map((file, index) => (
            <MenuItem key={index} value={file}>
              {file.name}
            </MenuItem>
          ))}
        </TextField>
        {props.currentUpload &&
        <Button color="primary" onClick={() => props.handleAttachmentDialogOpen(props.job.selectedUploads)}>
          Edit marker on image
        </Button>}
        {props.selectedMarkedImage &&
        <MarkedImage markerPosition={props.selectedMarkedImage.position}
                     attachment={props.selectedMarkedImage.attachment}
                     imageLoaded={props.markedImageLoaded}
                     handleImageLoaded={props.handleMarkedImageLoaded}
        />}
      </div>
    );
    
    const SelectedProductsChipContainer = (props) => (
      <div className={props.classes.wrapper}>
        <Typography type="subheading" gutterBottom>
          Selected Products
        </Typography>
        <div className={props.classes.chipContainer}>
          {props.selectedProducts.map((product, index) => {
            return (
              <Chip
                label={`${product.name} (${product.productQuantity})`}
                key={index}
                className={props.classes.chip}
                onRequestDelete={() => props.handleRequestDeleteChip(product, "product")}
              />
            )
          })}
        </div>
      </div>
    );
    
    const SelectedImagesView = (props) => (
      <div className={props.classes.wrapper}>
        <Typography type="subheading" gutterBottom>
          Selected images
        </Typography>
        <input type="file" id="myFile" onChange={props.handleFileUpload} />
        {props.uploadLoading
          ? <CircularProgress/>
          : null}
        {props.selectedUploads.length > 0 && <EntryImageView selectedUploads={props.selectedUploads}
                                                             handleRequestDeleteChip={props.handleRequestDeleteChip} />}
      </div>
    );
    
    const LocationDescriptionTextField = (props) => (
      <TextField
        id="locationDescription"
        label="Location Description"
        multiline
        rows="4"
        value={props.locationDescription}
        onChange={props.handleInputChange('locationDescription')}
        margin="normal"
        fullWidth
      />
    );
    
    const CommentsTextField = (props) => (
      <TextField
        id="comments"
        label="Comments"
        multiline
        rows="4"
        value={props.comments}
        onChange={props.handleInputChange('comments')}
        margin="normal"
        fullWidth
      />
    );
    
    
    export const CreateEntryForm = (props) => {
      const { classes } = props;
      return (
        <div>
          {props.job && <SelectedProductsGroup {...props} classes={classes}/>}
          {props.selectedProducts.length > 0 && <SelectedProductsChipContainer {...props} classes={classes}/>}
          {props.job && <ProductFormGroup {...props}/>}
          <SelectedImagesView {...props} classes={classes} />
          <LocationDescriptionTextField {...props} />
          <CommentsTextField {...props} />
          <Button color="primary" onClick={props.handleSubmit}>Create entry</Button>
        </div>
      )
    };
    
    export default withStyles(styles)(CreateEntryForm);
    

0 个答案:

没有答案