如何将仅具有1extra嵌套状态的状态应用于MongoDB

时间:2019-06-05 20:21:57

标签: node.js reactjs mongodb mern

我正在尝试对我的密码进行哈希处理时将输入值获取到mongoDB。

但是我的方案密码位于一个对象(localProvider)内部。 (这仅用于教育,这是我的老师编写的代码)

    {
        username: {
            type: String,
            required: false,
        },
        email: {
            type: String,
            required: true,
            trim: true,
            unique: true,
            match: /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/,
        },
        localProvider: {
            password: {
                type: String,
                required: false,
            },
        },
        facebookProvider: {
            id: { type: String, required: false },
            token: { type: String, required: false },
        },
        published_at: { type: Date, required: false },
        deleted_at: { type: Date, required: false },
    },
    {
        toJSON: { virtuals: true },
        toObject: { virtuals: true },
    },
    {
        timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
    },
);

UserSchema.methods.slugify = function () {
    this.slug = slug(this.email);
};

UserSchema.pre('validate', function (next) {
    if (!this.slug) {
        this.slugify();
    }
    return next();
});

UserSchema.pre('save', function (next) {
    const user = this;

    if (!user.isModified('localProvider.password')) return next();// only hash the password if it has been modified (or is new)

    try {
        return bcrypt.genSalt(config.auth.bcrypt.SALT_WORK_FACTOR, (errSalt, salt) => {
            if (errSalt) throw errSalt;

            return bcrypt.hash(user.localProvider.password, salt, (errHash, hash) => {
                if (errHash) throw errHash;

                user.localProvider.password = hash;
                return next();
            });
        });
    } catch (error) {
        return next(error);
    }
});

UserSchema.methods.comparePassword = function (candidatePassword, cb) {
    const user = this;
    bcrypt.compare(candidatePassword, user.localProvider.password, (err, isMatch) => {
        if (err) return cb(err, null);
        return cb(null, isMatch);
    });
};

UserSchema.virtual('id').get(function () { return this._id; });

UserSchema.plugin(mongoosePaginate);
export default mongoose.model('User', UserSchema);

我已经尝试在register.js中使用onChange传递输入值

[event.target.name]: event.target.value 只有这一行代码仅适用于单个值,而不适用于对象内部。 正如您在方案中所看到的那样,到目前为止,我知道无法将值传递给单个状态值和嵌套状态值。

因此,有解决方案来修复代码,以便我还能将用户名和电子邮件推送到状态,并在1 handleChange中将密码推送到localProvider吗?

来自register.js的代码

class Signup extends Component {
  constructor() {
        super()
        this.state = {
            username: '',
      email: '',
      redirectTo: null,
      localProvider:{
         password: ''

      }


    }

        this.handleSubmit = this.handleSubmit.bind(this)
    this.handleChange = this.handleChange.bind(this)
  }
  handleInputChange(event, value){
      this.setState({
        [event.target.name]: event.target.value
      })
  }
  handleChange(el) {
    let inputName = el.target.name;
    let inputValue = el.target.value;

    let statusCopy = Object.assign({}, this.state);
    statusCopy.localProvider[inputName].value = inputValue;

    this.setState(statusCopy);
  }
    handleSubmit(event) {
        console.log('sign-up handleSubmit, username: ')
        console.log(this.state.username)
        event.preventDefault()

        //request to server to add a new username/password
        axios.post('/api/v1/users/', {
            ...this.state
        })
            .then(response => {
                console.log(response)
                if (!response.data.errmsg) {
          console.log('successful signup')
          this.props.history.push("/");
                } else {
                    console.log('username already taken')
                }
            }).catch(error => {
                console.log('signup error: ')
                console.log(error)

            })
  }  
  render() {
    const { classes } = this.props;



    return (
      <React.Fragment>
        <CssBaseline />
        <Paper className={classes.paper}>
          <Avatar className={classes.avatar}>
            <LockOutlinedIcon />
          </Avatar>
          <Typography component="h1" variant="h5">
            Sign in
          </Typography>
          <form  className={classes.form}>
          <FormControl margin="normal" required fullWidth>
              <InputLabel htmlFor="name">Name</InputLabel>
              <Input name="username" type="text" id="username"  autoComplete="username" onChange={this.handleInputChange}  />
            </FormControl>
            <FormControl margin="normal" required fullWidth>
              <InputLabel htmlFor="email">Email Address</InputLabel>
              <Input id="email" name="email" autoComplete="email" onChange={this.handleInputChange} />
            </FormControl>
            <FormControl margin="normal" required fullWidth>
              <InputLabel htmlFor="password">Password</InputLabel>
              <Input type="password" id="password" autoComplete="current-password" onChange={this.handleChange} name="password"/>
            </FormControl>
            <FormControlLabel
              control={<Checkbox value="remember" color="primary" />}
              label="Remember me"
            />
            <Button
              type="submit"
              fullWidth
              variant="contained"
              color="primary"

            >
              Sign in
            </Button>
          </form>
        </Paper>
      </React.Fragment>
    )
  }
}

export default withStyles(styles)(Signup);```

1 个答案:

答案 0 :(得分:1)

  handleChange(el) {
    let inputName = el.target.name;
    let inputValue = el.target.value;

    let providerCopy = Object.assign({}, this.state.localProvider); // new
    let statusCopy = Object.assign({}, this.state, {localProvider: providerCopy}); //edited
    statusCopy.localProvider[inputName].value = inputValue;

    this.setState(statusCopy);
  }

Object.assign()仅复制到一个级别深,而您需要将复制深度复制到2个级别,因此您可以使用两次或在对象上使用散布运算符。

let nextState = {...this.state, localProvider: {...this.state.localProvider, [el.target.name]: [el.target.value] } };
this.setState(nextState);

请查看here,以获取有关嵌套状态更改的更多信息。