Передача константы в действие и ее доступность для отправки на серверную часть

#reactjs #mongoose #redux #react-router

#reactjs #мангуст #сокращение #реагировать-маршрутизатор

Вопрос:

Я пытаюсь получить константу resetLink (токен JWT), отправленную с динамического URL (/api/ users/resetpassword/:resetLink) после того, как пользователь сбросит свой пароль.

в componendDidMount я вызываю «this.props.startPassReset (resetlink)», где кажется, что resetLink потерян, и я не могу отследить его через какие-либо параметры / реквизиты / состояние.

PassResetForm.js

 
import React, { Component } from 'react';
import {
    Button,
    Row,
    Col,
    Modal,
    ModalHeader,
    ModalBody,
    Form,
    FormGroup,
    Label,
    Input,
    NavLink,
    Alert,
    Container,
} from "reactstrap";
import { connect } from 'react-redux'

import PropTypes from "prop-types";
import { register, passReset, startPassReset } from "../../actions/authActions";
import { clearErrors } from "../../actions/errorActions";

class PassResetForm extends Component {
    state = {
        modal: false,
        name: "",
        email: "",
        password: "",
        msg: null,
        resetLink: "test",
    };

    static propTypes = {
        isAuthenticated: PropTypes.bool,
        error: PropTypes.object.isRequired,
        resetLink: PropTypes.string.isRequired,
        clearErrors: PropTypes.func.isRequired,
    };

    componentDidMount() {
        // Idea here is to get the token, and set it to resetLink, and pass that to the Action when the component mounts
        const { resetLink } = this.props.match.params;
        const { error, isAuthenticated } = this.props;
        
        if (!resetLink) {
            console.log("!resetLink");
            this.setState({ msg: "Token error" });
        } else {          

            console.log("resetLink!");
            this.setState({
                resetLink: resetLink
            }, (resetLink) => {
                console.log("updated state:", resetLink)
                console.log("resetLink state within: "   this.state.resetLink);
                this.props.startPassReset(resetLink);
            });
            console.log("resetLink is: "   resetLink);
        }
    }    

    componentDidUpdate(prevProps) {
        const { error, isAuthenticated, auth } = this.props;

        if (auth !== prevProps.auth) {
            if (auth.msg !== null) {
                this.setState({ msg: auth.msg })
            } else {
                this.setState({ msg: null });
            }
        }
        if (error !== prevProps.error) {
            // Check for register error
            if (error.id === "RESET_FAIL") {
                this.setState({ msg: error.msg.msg });
            } else {
                this.setState({ msg: null });
            }
        }
    }

    toggle = () => {
        console.log();
        // startPassReset();

        this.setState({
            modal: !this.state.modal,
        });
    };

    onChange = (e) => {
        this.setState({ [e.target.name]: e.target.value });
    };

    onSubmit = (e) => {
        e.preventDefault();

        const { newPass, newPassMatch } = this.state;
        if (newPass !== newPassMatch) {
            this.setState({ msg: "Passwords don't match." })
        } else {
            console.log("newPass and newPassMatch are "   newPass   newPassMatch)
            this.props.passReset(newPass);
        }
    };

    // DONE Make an api call to your backend that creates a password reset token. Store it in the database and, in one form or another, associate it with the user (usually it's the same database entry).

    // DONE Send an email to the user with a link that has the password reset token embedded into it. Have a route in your react-router routes that will handle the url you link to.

    // Have the route mount a component that has a componentDidMount, which takes the token and makes an api to the backend to validate the token.

    // Once validated, open a ui element in the react component that allows the user to set a new password

    // Take the new password, password confirmation, and reset token and make an api call to the backend to change the password. You need the token a second time because you have to validate the token one last time during the actual password change process, to make sure no one is attempting anything malicious. Hiding inputs behind state is not secure.

    // DONE Delete the reset token in the backend after successful password change

    render() {
        const { isAuthenticated } = this.props;
        return (
            <div>
                {isAuthenticated ? null : (
                    <Container>
                        <Row>
                            <Col sm="12" md={{ size: 6, offset: 3 }}>
                                {this.state.msg ? (
                                    <Alert align="center" color="danger">{this.state.msg}</Alert>
                                ) : (
                                        <>
                                            <Button onClick={this.toggle} color="dark" style={{ marginTop: "2rem" }} block>
                                                Reset Password
                                </Button>
                                            <Modal isOpen={this.state.modal} toggle={this.toggle}>
                                                <ModalHeader>
                                                    <h2 align="center">Reset Password</h2>
                                                    {this.state.msg ? (
                                                        <Alert align="center" color="danger">{this.state.msg}</Alert>
                                                    ) : null}
                                                </ModalHeader>
                                                <Row>
                                                    <Col sm="12" md={{ size: 6, offset: 3 }}>
                                                        <Form onSubmit={this.onSubmit}>
                                                            <FormGroup>
                                                                <Label for="email">Enter your new password</Label>
                                                                <Input
                                                                    type="password"
                                                                    name="newPass"
                                                                    id="newPass"
                                                                    placeholder="New Password"
                                                                    onChange={this.onChange}
                                                                />
                                                                <Input
                                                                    type="password"
                                                                    name="newPassMatch"
                                                                    id="newPassMatch"
                                                                    placeholder="Retype New Password"
                                                                    onChange={this.onChange}
                                                                />
                                                                <Button color="dark" style={{ marginTop: "2rem" }} block>
                                                                    Submit New Password
                                                    </Button>
                                                            </FormGroup>
                                                        </Form>
                                                    </Col>
                                                </Row>
                                            </Modal>
                                        </>
                                    )}
                            </Col>
                        </Row>

                    </Container>
                )
                }

            </div>
        )
    }
}

const mapStateToProps = (state) => ({
    error: state.error,
    auth: state.auth,
    resetLink: state.resetLink,
})


export default connect(mapStateToProps, { passReset, clearErrors, startPassReset })(PassResetForm)

  

App.js

 import React, { Component } from 'react';
import { BrowserRouter as Router, Link, Route } from 'react-router-dom';
import AppNavbar from './components/AppNavbar';
import { Provider } from 'react-redux';
import store from './store';
import { Container } from 'reactstrap';
import { loadUser } from './actions/authActions';

import 'bootstrap/dist/css/bootstrap.min.css';
import './App.css';
import PassResetForm from './components/auth/PassResetForm';

class App extends Component {
  componentDidMount() {
    store.dispatch(loadUser());
  }

  render() {
    return (
      <Router>
        <Provider store={store}>
          <div className="App">
            <AppNavbar />
            <Container>
              <Route exact={true} path="/api/users/resetpassword/:resetLink" component={PassResetForm} />
              

            </Container>
          </div>
        </Provider>
      </Router>
    );
  }

}

export default App;
  

authActions.js (Этот код неполон, но ранее работал в другом формате при добавлении токена вручную)

 export const startPassReset = () => async dispatch => {
  // const resetLink = "derp"; Adding tokens here manually to check the pathway, and it has worked before.
  dispatch({ 
    type: START_PASS_RESET
   });

  console.log("startPassReset Begins");

  axios
    .get('/api/users/resetpassword/'   resetLink, {})
    .then(res =>
      dispatch({
        type: RESET_TOKEN_SUCCESS,
        payload: res.data
      })
    )
    .catch(err => {
      dispatch(
        returnErrors(err.response.data, err.response.status, 'RESET_FAIL')
      );
      dispatch({
        type: RESET_FAIL
      });
    });
}
  

authReducer.js

     case START_PASS_RESET:
      return {
        ...state,
        token: null,
        user: null,
        isAuthenticated: false,
        isLoading: false,
      }
  

Наконец, users.js (Серверная часть, это работает при отправке вручную)

 router.get('/resetpassword/:resetlink', (req, res) => {
  
  console.log("req.params: "   JSON.stringify(req.params));
  console.log("req.body "   JSON.stringify(req.body));
  const resetLink = req.params.resetlink;
  console.log("resetLink? "   resetLink);
  // verify the reset link is genuine
  jwt.verify(resetLink, process.env.JWT_SECRET, function (err, decodedData) {
    if (err) {
      return res.status(401).json({ msg: "Incorrect token or it is expired. "   err });
    } else {
      User.findOne({ resetLink }, (err, user) => {
        if (err || !user) {
          return res.status(400).json({ msg: "User with this token doesn't exist" });
        } else {
          // Success condition. Go ahead and allow the form to appear to reset the password
          console.log("Hi there, you made it! "   resetLink)
          return res.status(200).json({ msg: "I like what you got, good job!" })
        }
      })
    }
  })
});
  

Я действительно столкнулся с этим и ценю любую помощь.

Ответ №1:

Оказывается, моя ошибка была в первой строке AuthActions. А именно:

 export const startPassReset = (resetLink) => async dispatch => {
  

Сумасшедший. Моя ошибка. Оставлю здесь на случай, если другие что-то получат от этого.