使用Firebase存储数据时,如何避免获得过多的递归?

时间:2018-09-17 00:34:34

标签: javascript reactjs firebase firebase-realtime-database

我正在仅使用React.js,material-ui和firebase创建一个小型应用程序。我现在不想使用Redux以便对React更加熟悉。 我创建了一个表单,描述如下:

User.jsx:

import React, { Component } from 'react'
import Button from '@material-ui/core/Button'
import Grid from '@material-ui/core/Grid';
import { withStyles } from '@material-ui/core/styles';
import PropTypes from 'prop-types';
import Typography from '@material-ui/core/Typography';
import moment from 'moment';
import db from '../db/config';
import InputTextField from './textField';
import RadioGroup from './radioGroup';
import SnackBar from './snackBar';


const styles = (theme) => ({
  button: {
    margin: theme.spacing.unit,
  },
  root: {
    display: 'flex',
    marginTop: theme.spacing.unit * 8,
    padding: theme.spacing.unit * 3,
  },
  item: {
    padding: theme.spacing.unit * 2
  }
});

class User extends Component {
  state = {
    birthday: moment().format('YYYY-MM-DD'),
    message: '',
    name: '',
    open: false,
    gender: 'male',

  };

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

  handleClose = (event, reason) => {
    if (reason === 'clickaway') {
      return;
    }

    this.setState({ open: false });
  };

  handleSubmit = (event) => {
    event.preventDefault();
    const { 
      birthday,
      name,
      gender,
  } = this.state;
    console.log(`birthday: ${birthday} \n` + 
  `Name: ${name} \n` + 
  `gender: ${gender} \n`)


  const ref = db.ref('users/');

  ref.orderByChild('name').on('child_added', (snapshot) => {
    const existedName = (snapshot.val().name).toLowerCase().trim();
    const newName = name.toLowerCase().trim();
    if(existedName === newName){
      this.setState({
        open: true,
        message: 'Name already exists!!',
      })
    } else {
      ref.push({
        name: name.trim(),
        gender,
        birthday
    })
    .then(() => {
      this.setState({
        open: true,
        message: 'saved successfully!!',
      })
      return true;
    })
    .catch((error) => {
      this.setState({
        open: true,
        message: `Error adding baby: ${error}`,
      })
      return false;
    });
    }
  })
  }

  render(){
    const { classes } = this.props;
    const { 
      birthday,
      message,
      name,
      open,
      gender,
     } = this.state;
    return (
      <div className={classes.root}>
        <Grid 
          container 
          spacing={40}
          justify='center'
          direction="column"
          alignItems="center"
        >
          {open && (
          <SnackBar
            handleClose={this.handleClose}
            message={message}
            open
          />
          )}
          <Typography 
            align="center"
            gutterBottom
            variant="title"
          >
          Add New User
          </Typography> 

          <form onSubmit={this.handleSubmit} className={classes.form}>
            <Grid item className={classes.item} xs={12}>
              <InputTextField 
                label="Name"
                handleChange={this.handleChange('name')}
                required
                value={name}
                type="text"
              />
            </Grid>
            <Grid item className={classes.item}>
              <InputTextField 
                label="Birthday"
                handleChange={this.handleChange('birthday')}
                required
                value={birthday}
                type="date"
                InputLabelProps={{shrink: true}}
              />
            </Grid>
            <Grid item className={classes.item}>
              <RadioGroup 
                name="Gender"
                handleChange={this.handleChange('gender')}
                value={gender}
              />
            </Grid>
            <Grid item className={classes.item}>
              <Grid
                container
                direction="row"
              >
                <Grid item>
                  <Button 
                    variant="contained" 
                    color="primary" 
                    className={classes.button}
                  >
            Cancel
                  </Button>
                </Grid>
                <Grid item>
                  <Button 
                    variant="contained" 
                    color="primary" 
                    className={classes.button}
                    type='submit'
                  >
            Save
                  </Button>
                </Grid>
              </Grid>
            </Grid>
          </form>
        </Grid>
      </div>

    )
  }
}
User.propTypes = {
  classes: PropTypes.object.isRequired,
}

export  default withStyles(styles)(User);

SnackBar.jsx:

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Snackbar from '@material-ui/core/Snackbar';
import IconButton from '@material-ui/core/IconButton';
import CloseIcon from '@material-ui/icons/Close';

const styles = theme => ({
  close: {
    width: theme.spacing.unit * 4,
    height: theme.spacing.unit * 4,
  },
});

const SimpleSnackbar = (props) => {
    const { 
        classes,
        handleClose,
        message,
        open,
     } = props;

    return (
      <div>
        <Snackbar
          anchorOrigin={{
            vertical: 'bottom',
            horizontal: 'left',
          }}
          open={open}
          autoHideDuration={6000}
          onClose={handleClose}
          ContentProps={{
            'aria-describedby': 'message-id',
          }}
          message={<span id="message-id">{message}</span>}
          action={[
            <Button key="undo" color="secondary" size="small" onClick={handleClose}>
              UNDO
            </Button>,
            <IconButton
              key="close"
              aria-label="Close"
              color="inherit"
              className={classes.close}
              onClick={handleClose}
            >
              <CloseIcon />
            </IconButton>,
          ]}
        />
      </div>
    );
}

SimpleSnackbar.propTypes = {
  classes: PropTypes.object.isRequired,
  handleClose: PropTypes.func.isRequired,
  message: PropTypes.string.isRequired,
  open: PropTypes.bool.isRequired,
};

export default withStyles(styles)(SimpleSnackbar);

输入表单的其他属性时,在控制台中收到以下警告:Firebase Warning

已添加到Firebase: too much recursion描述的消息too much recursion

我是Firebase的初学者,这是我使用它的第一个应用程序。我认为我错过了一些东西,或者我没有使用合适的功能来获取给定名称是否已经存在。除非将其保存。如果有人试图帮助我解决警告和控制台上显示的错误,我将不胜感激。

1 个答案:

答案 0 :(得分:0)

我尝试了此解决方案,并且有效:

handleSubmit = (event) => {
event.preventDefault();
const { 
  birthday,
  name,
  gender,
} = this.state;

const ref = db.ref('users/');

const onChildAdded = (snapshot) => {
  if(snapshot.exists()){
    this.setState({
      open: true,
      message: 'Name already exists!!',
    })
  } else {
    ref.push({
      name: name.trim(),
      gender,
      birthday
  })
  .then(() => {
    this.setState({
      open: true,
      message: 'saved successfully!!',
    })
    return true;
  })
  .catch((error) => {
    this.setState({
      open: true,
      message: `Error adding baby: ${error}`,
    })
    return false;
  });
  }
}

ref.orderByChild('name').equalTo(name).once('value').then(onChildAdded);
  }