Отображать сообщение сервера при начальной загрузке избыточной формы

Мне нужно, чтобы сообщение redux-form-toaster отображалось при первом нажатии кнопки отправки при первой загрузке формы. Сообщение тостера отображается при втором нажатии кнопки отправки. Я знаю, что есть проблема с жизненным циклом компонента, которую мне нужно решить, но я не могу ее точно определить.

Вот мой файл register.js:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import { Link } from 'react-router';
import { registerUser } from '../../actions/auth';
import Notifications, {notify} from 'react-notify-toast';
import Input from '../common/Input';

const form = reduxForm({
  form: 'register',
  fields: ['firstName', 'lastName', 'email', 'password'],
  validate
});

const selector = formValueSelector('register');

function validate(formProps) {
  const errors = {};

  if (!formProps.firstName) {
    errors.firstName = 'Please enter a first name';
  }

  if (!formProps.lastName) {
    errors.lastName = 'Please enter a last name';
  }

  if (!formProps.email) {
    errors.email = 'Please enter an email';
  } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(formProps.email)) {
    errors.email = 'Invalid email address format';
  }

  if (!formProps.password) {
    errors.password = 'Please enter a password';
  }

  return errors;
}


class Register extends Component {
  handleFormSubmit(formProps) {
    this.props.registerUser(formProps);
  }

  renderServerAlert() {
    if (this.props.errorMessage) {
      return (
        <div>
          {notify.show(this.props.errorMessage, 'error', 5000)}
        </div>
      )
    }
  }

  render() {
    const { email, handleSubmit, submitting } = this.props;

    return (
      <div>
        <div className="middle-box text-center loginscreen" style={{position: 'absolute', top: -30, marginLeft: 'auto', marginRight: 'auto', left: 0, right: 0}}>
          <h2 style={{fontWeight: 500}} className="text-muted">Register</h2>
            <Notifications />
            <form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
              <Field name="firstName" component={Input} type="text" label="Firstname" />
              <Field name="lastName" component={Input} type="text" label="Lastname" />
              <Field name="email" component={Input} type="text" label="Email" />
              <Field name="password" component={Input} type="password" label="Password" />
              <button action="submit" disabled={submitting} onClick={() => {this.renderServerAlert()}} className="btn btn-primary block full-width m-b">Register</button>
          <p className="text-muted text-center">Already have an account?</p>
              <Link className="btn btn-sm btn-white btn-block" to="/login">Login</Link>
            </form>
            <p className="m-t"> MyCopany Business Application Starter &copy; 2017 </p>
        </div>
        <div className="footer" style={{zIndex: 999, position: 'fixed', bottom: 0}}>
          <div className="pull-right">
            <strong>MyCompany</strong> Always Free.
          </div>
          <div>
            <strong>Copyright</strong> MyCompany &copy; 2016-2017
          </div>
        </div>
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    errorMessage: state.auth.error,
    message: state.auth.message,
    authenticated: state.auth.authenticated
  };
}

export default connect(mapStateToProps, { registerUser })(form(Register));

Вот мой файл действий auth.js:

import axios from 'axios';
import { browserHistory } from 'react-router';
import cookie from 'react-cookie';
import { API_URL, CLIENT_ROOT_URL, errorHandler } from './index';
import { AUTH_USER, AUTH_ERROR,  UNAUTH_USER, FORGOT_PASSWORD_REQUEST, RESET_PASSWORD_REQUEST, PROTECTED_TEST } from './types';

//================================
// Authentication actions
//================================

// TO-DO: Add expiration to cookie
export function loginUser({ email, password }) {
  return function(dispatch) {
    axios.post(`${API_URL}/auth/login`, { email, password })
    .then(response => {
      cookie.save('token', response.data.token, { path: '/' });
      cookie.save('user', response.data.user, { path: '/' });
      dispatch({ type: AUTH_USER });
      window.location.href = CLIENT_ROOT_URL + '/dashboard';
    })
    .catch((error) => {
      errorHandler(dispatch, error.response, AUTH_ERROR)
    });
    }
  }

export function registerUser({ email, firstName, lastName, password }) {
  return function(dispatch) {
    axios.post(`${API_URL}/auth/register`, { email, firstName, lastName, password })
    .then(response => {
      cookie.save('token', response.data.token, { path: '/' });
      cookie.save('user', response.data.user, { path: '/' });
      dispatch({ type: AUTH_USER });
      window.location.href = CLIENT_ROOT_URL + '/dashboard';
    })
    .catch((error) => {
      errorHandler(dispatch, error.response, AUTH_ERROR)
    });
  }
}

export function logoutUser(error) {
  return function (dispatch) {
    dispatch({ type: UNAUTH_USER });
    cookie.remove('token', { path: '/' });
    cookie.remove('user', { path: '/' });

    window.location.href = CLIENT_ROOT_URL + '/login';
  }
}

export function getForgotPasswordToken({ email }) {
  return function(dispatch) {
    axios.post(`${API_URL}/auth/forgot-password`, { email })
    .then(response => {
      dispatch({
        type: FORGOT_PASSWORD_REQUEST,
        payload: response.data.message
      });
    })
    .catch((error) => {
      errorHandler(dispatch, error.response, AUTH_ERROR)
    });
  }
}

export function resetPassword( token, { password }) {
  return function(dispatch) {
    axios.post(`${API_URL}/auth/reset-password/${token}`, { password })
    .then(response => {
      dispatch({
        type: RESET_PASSWORD_REQUEST,
        payload: response.data.message
      });
      // Redirect to login page on successful password reset
      browserHistory.push('/login');
    })
    .catch((error) => {
      errorHandler(dispatch, error.response, AUTH_ERROR)
    });
  }
}

export function protectedTest() {
  return function(dispatch) {
    axios.get(`${API_URL}/protected`, {
      headers: { 'Authorization': cookie.load('token') }
    })
    .then(response => {
      dispatch({
        type: PROTECTED_TEST,
        payload: response.data.content
      });
    })
    .catch((error) => {
      errorHandler(dispatch, error.response, AUTH_ERROR)
    });
  }
}

...и, наконец, серверный контроллер:

"use strict";

const jwt = require('jsonwebtoken'),
      crypto = require('crypto'),
      User = require('../models/user'),
      mailgun = require('../config/mailgun'),
      mailchimp = require('../config/mailchimp'),
      config = require('../config/main');

// Generate JWT
// TO-DO Add issuer and audience
function generateToken(user) {
  return jwt.sign(user, config.secret, {
    expiresIn: 10080 // in seconds
  });
}

// Set user info from request
function setUserInfo(request) {
  let getUserInfo = {
    _id: request._id,
    firstName: request.profile.firstName,
    lastName: request.profile.lastName,
    email: request.email,
    role: request.role,
  };

  return getUserInfo;
}

//========================================
// Login Route
//========================================
exports.login = function(req, res, next) {

  let userInfo = setUserInfo(req.user);

  res.status(200).json({
    token: 'JWT ' + generateToken(userInfo),
    user: userInfo
  });
}


//========================================
// Registration Route
//========================================
exports.register = function(req, res, next) {
  // Check for registration errors
  const email = req.body.email;
  const firstName = req.body.firstName;
  const lastName = req.body.lastName;
  const password = req.body.password;

  // Return error if no email provided
  if (!email) {
    return res.status(422).send({ error: 'You must enter an email address.'});
  }

  // Return error if full name not provided
  if (!firstName || !lastName) {
    return res.status(422).send({ error: 'You must enter your full name.'});
  }

  // Return error if no password provided
  if (!password) {
    return res.status(422).send({ error: 'You must enter a password.' });
  }

  User.findOne({ email: email }, function(err, existingUser) {
      if (err) { return next(err); }

      // If user is not unique, return error
      if (existingUser) {
        return res.status(422).send({ error: 'Email address already exists.' });
      }

      // If email is unique and password was provided, create account
      let user = new User({
        email: email,
        password: password,
        profile: { firstName: firstName, lastName: lastName }
      });

      user.save(function(err, user) {
        if (err) { return next(err); }

        // Subscribe member to Mailchimp list
        // mailchimp.subscribeToNewsletter(user.email);

        // Respond with JWT if user was created

        let userInfo = setUserInfo(user);

        res.status(201).json({
          token: 'JWT ' + generateToken(userInfo),
          user: userInfo
        });
      });
  });
}

//========================================
// Authorization Middleware
//========================================

// Role authorization check
exports.roleAuthorization = function(role) {
  return function(req, res, next) {
    const user = req.user;

    User.findById(user._id, function(err, foundUser) {
      if (err) {
        res.status(422).json({ error: 'No user was found.' });
        return next(err);
      }

      // If user is found, check role.
      if (foundUser.role == role) {
        return next();
      }

      res.status(401).json({ error: 'You are not authorized to view this content.' });
      return next('Unauthorized');
    })
  }
}

//========================================
// Forgot Password Route
//========================================

exports.forgotPassword = function(req, res, next) {
  const email = req.body.email;

  User.findOne({ email: email }, function(err, existingUser) {
    // If user is not found, return error
    if (err || existingUser == null) {
      res.status(422).json({ error: 'Your request could not be processed as entered. Please try again.' });
      return next(err);
    }

      // If user is found, generate and save resetToken

      // Generate a token with Crypto
      crypto.randomBytes(48, function(err, buffer) {
        const resetToken = buffer.toString('hex');
        if (err) { return next(err); }

        existingUser.resetPasswordToken = resetToken;
        existingUser.resetPasswordExpires = Date.now() + 3600000; // 1 hour

        existingUser.save(function(err) {
          // If error in saving token, return it
          if (err) { return next(err); }

          const message = {
            subject: 'Reset Password',
            text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
            'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
            'http://' + req.headers.host + '/reset-password/' + resetToken + '\n\n' +
            'If you did not request this, please ignore this email and your password will remain unchanged.\n'
          }

          // Otherwise, send user email via Mailgun
          mailgun.sendEmail(existingUser.email, message);

          res.status(200).json({ message: 'Please check your email for the link to reset your password.'});
          next();
        });
      });
  });
}

//========================================
// Reset Password Route
//========================================

exports.verifyToken = function(req, res, next) {
  User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, resetUser) {

    // If query returned no results, token expired or was invalid. Return error.
      if(!resetUser) {
        res.status(422).json({ error: 'Your token has expired. Please attempt to reset your password again.' });
      }

      // Otherwise, save new password and clear resetToken from database
      resetUser.password = req.body.password;
      resetUser.resetPasswordToken = undefined;
      resetUser.resetPasswordExpires = undefined;

      resetUser.save(function(err) {
        if (err) { return next(err); }

        // If password change saved successfully, alert user via email
        const message = {
          subject: 'Password Changed',
          text: 'You are receiving this email because you changed your password. \n\n' +
          'If you did not request this change, please contact us immediately.'
        }

        // Otherwise, send user email confirmation of password change via Mailgun
        mailgun.sendEmail(resetUser.email, message);

        res.status(200).json({ message: 'Password changed successfully. Please login with your new password.'});
        next();
      });
  });
}

Все работает идеально (по второму клику)


person user2078922    schedule 12.11.2016    source источник


Ответы (1)


это не проблема кода. Если вы используете отладчик, вы заметите, что Redux React использует неправильный локальный хост для серверной части.

xhr.js:173 POST http://localhost:3000/api/XXX 401 (Неавторизованный). вот почему вы получаете ошибку

person Jude Okagu    schedule 20.03.2019