Getting URL Parameters on GatsbyJS
Asked Answered
J

2

21

Is there a way to retrieve url parameters passed on pages of project built on GatsbyJS? I'm trying to implement a password reset function on my page using AWS, but they can only send the parameters through a link sent to the user's email.

So the flow would be like this :

User triggers Forgot Password -> AWS sends email to user with link -> Link directs to my page with the parameters -> Reset password form automatically populates fields with the parameters passed

Update

Here's my App.js code :

import { Router } from "@reach/router"


const App = () => (
  <Layout>
    <Router>
      <Login path="signin" exact component={Login} />
      <Resources path="api/resources" exact component={Resources} />
      <Verify path="verify" exact component={Verify} />
      <Forgot path="forgot" exact component={Forgot} />
      <Reset path="account/reset/:code" exact component={Reset}/>
    </Router>
  </Layout>
)

export default App;

Reset.js :

export default class ResetForm extends Component {
    constructor(props) {
        super(props);

        this.state = {
            password: "",
            confirmPassword: "",
            vercode: "",
            email: "",
            emailValid: false,
            passValid: false,
            confirmValid: false,
            codeValid: false,
            formValid: true,
            formErrors : {
                email: false,
                password: false,
                confirmPassword: false,
                vercode: false,
            },
            respErrors : {
                email: {
                    isValid : true,
                    message : ""
                },
                password: {
                    isValid : true,
                    message : ""
                },
                code : {
                    isValid : true,
                    message : ""
                }
            }

        };

    }

    validateField(field, value) {

        let password = this.state.password
        let fieldValidationErrors = this.state.formErrors;
        let emailValid = this.state.emailValid
        let passValid = this.state.passValid
        let confirmValid = this.state.confirmValid
        let codeValid = this.state.vercode
        let fieldValidationMessages = this.state.respErrors;


        switch(field){
            case 'email' :
                emailValid = validator.isEmail(value);
                fieldValidationErrors.email = emailValid ? false : true;
                fieldValidationMessages.email.isValid = true;
                fieldValidationMessages.email.message = "Invalid E-Mail Address";
                break;

            case 'password' :
                passValid = validator.matches(value, RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*])(?=.{8,})'));

                fieldValidationMessages.password.message = passValid ? '' : undefined;

                if(!validator.matches(value,RegExp('^(?=.*[a-z])(?=.*[A-Z])'))){
                    fieldValidationMessages.password.message = "At least 1 Upper case character is required";
                }

                if(!validator.matches(value,RegExp('^(?=.*[!@#$%^&*])'))){
                    fieldValidationMessages.password.message = "At least 1 Symbol is required";
                }

                if(!validator.matches(value,RegExp('^(?=.{8,})'))){
                    fieldValidationMessages.password.message = "Password must have at least 8 characters";
                }


                fieldValidationErrors.password = passValid ? false : true;
                break;

            case 'confirmPassword' :
                confirmValid = validator.equals(value, password);
                fieldValidationErrors.confirmPassword = confirmValid ? false : true;
                break;

            case 'vercode' :
                codeValid = !validator.isEmpty(value);
                fieldValidationErrors.vercode = codeValid ? false : true;
                break;

            default :

                break
            }

        this.setState({
            formErrors: fieldValidationErrors,
            emailValid: emailValid,
            passValid: passValid,
            confirmValid: confirmValid,
            codeValid: codeValid,
        }, this.validateForm())

    }

    validateForm(){
        this.setState({
            formValid: 
                this.state.emailValid && this.state.confirmValid && this.state.codeValid && this.state.passValid
        })

    }

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


    handleSubmit = async (event) => {
        event.preventDefault()
        const state = this.state

        await handleReset(state)
        .then(async (data) => {
            if(data.isValid){
                await handleLogin(state)
                .then(() => {
                    navigate('/')
                })
                .catch(err => console.log(err))
            } else {
                switch (data.code) {
                    case CODE_RESET.RESET_EXPIRED:
                        data.message = "The verification code you have submitted is already expired."
                        break
                    case CODE_RESET.RESET_MISMATCH:
                        data.message = "The verification code you have submitted is invalid."
                        break

                    default:
                        data.message = "Something went wrong."
                        break;
                }

                this.setState({
                    [state.respErrors.code.isValid] : data.isValid,
                    [state.respErrors.code.message] : data.message
                })
            }
        })
        .catch(async(err) => {
            console.log(err)
        })

    }

  render() {
        if(isLoggedIn()) {
            navigate(`/`)
        }

        return (

            <Row className={[formStyles.formContainer, "row"].join(' ')} >
            <Col sm={{
                size:12
                }}
                md={{
                    size: 8,
                    offset: 2
                }}
            >
                <Form 
                    onSubmit={this.handleSubmit} 
                >
                    <h3 style={{
                        fontWeight: 'bolder'
                    }}>
                        Reset Password
                    </h3>
                    <FormGroup>
                        <Label for="email">Email</Label>
                        <Input
                            id="email"
                            autoFocus
                            type="email"
                            name="email"
                            value={this.state.email.value}
                            onChange={this.handleChange}
                            className={formStyles.signUp} 
                            valid={this.state.emailValid}
                            invalid={(this.state.formErrors.email || !this.state.respErrors.email.isValid ) ? true : undefined}
                        />
                        <FormFeedback invalid={this.state.respErrors.email.isValid ? '' : undefined}>
                            {this.state.respErrors.email.message}
                        </FormFeedback>
                    </FormGroup>

                    <FormGroup>
                        <Label for="password">New Password</Label>
                        <Input
                            id="password"
                            type="password"
                            name="password"
                            value={this.state.password.value}
                            onChange={this.handleChange}
                            className={formStyles.signUp} 
                            valid={this.state.passValid }
                            invalid={this.state.formErrors.password ? true : undefined}
                        />
                        <FormText invalid={this.state.respErrors.password.isValid ? '' : undefined}>
                            {this.state.respErrors.password.message}

                        </FormText>
                    </FormGroup>
                    <FormGroup>
                        <Label for="confirmPassword">Confirm Password</Label>
                        <Input
                            id="confirmPassword"
                            type="password"
                            name="confirmPassword"
                            value={this.state.confirmPassword.value}
                            onChange={this.handleChange}
                            className={formStyles.signUp}
                            valid={this.state.confirmValid }
                            invalid={this.state.formErrors.confirmPassword ? true : undefined}
                        />
                        <FormFeedback
                            invalid={this.state.formErrors.confirmPassword ? '' : undefined}
                        >
                            Password does not match    
                        </FormFeedback>

                    </FormGroup>

                    <FormGroup>
                        <Label for="vercode">Verification Code</Label>
                        <Input
                            id="vercode"
                            type="text"
                            name="vercode"
                            maxLength={6}
                            value={this.state.vercode.value}
                            onChange={this.handleChange}
                            className={formStyles.signUp} 
                            valid={this.state.codeValid.value }
                            invalid={this.state.formErrors.vercode || !this.state.respErrors.code.isValid ? true : undefined}
                        />
                        <FormFeedback invalid={this.state.respErrors.code.isValid ? '' : undefined} >
                            {this.state.respErrors.code.message}
                        </FormFeedback>
                    </FormGroup>

                    <Button 
                        color="primary"
                        disabled={!this.state.formValid}
                    >
                        Submit
                    </Button>
                </Form>
            </Col>
      </Row>
    )
  }
}
Juanjuana answered 16/12, 2018 at 7:12 Comment(7)
By default I believe gatsby uses reach router, but the way it's configured doesn't leave much to play around with if you haven't done some customization to it. Here are the reach router docs: reach.tech/router are you able to get what you need just by querying location?Blab
I tried to use that and console.log(this.props), but it returned empty.Juanjuana
as for the @reach/router, I am using it and placed it in my App.js so when user navigates to my page, I let it import the page container and also need to pass the query details to itJuanjuana
If you can share some of your code that would be much more helpful.Blab
I've updated the original post with the App.js code I have @JoshuaTerrillJuanjuana
Lex, could you also post the code to the Reset component?Blab
I just updated it now, apologies for the delay @JoshuaTerrillJuanjuana
S
25

Use URLSearchParams.get() as described on MDN:

// Get the location object that is implicitly passed as props 
// for every page in the `pages` folder
const Index = ({ location }) => { 
  console.log(location); // inspect location for yourself

  // the parameter to return for URL. Example: 
  // https://localhost:8000/?parameter1=firstParam&parameter2=secondParam
  const params = new URLSearchParams(location.search);
  const parameter1 = params.get("parameter1");
  const parameter2 = params.get("parameter2");

  console.log(parameter1); // -> "firstParam"
  console.log(parameter2); // -> "secondParam"
  // ...

Alternative: package query-string

yarn add query-string or npm i --save query-string

import * as queryString from "query-string";

// Get the location object that is implicitly passed as props 
// for every page in the `pages` folder
const Index = ({ location }) => { 
  console.log(location); // inspect location for yourself

  // query-string parses the parameters that are contained in the location object
  const { parameter1, parameter2 } = queryString.parse(location.search);

  console.log(parameter1);
  console.log(parameter2);
  // ...
Saltatory answered 16/5, 2020 at 12:58 Comment(1)
I think for gatsby v4, the query-string package is bundled together. so no need to do an npm -i.Develop
Z
18

Use props.location, introduced in Gatsby v2. It's made available by @reach/router to all components via props.

function Component(props) {
  // use props.location...
  return ...
}
Zahara answered 12/1, 2019 at 16:51 Comment(1)
I was able to fix this using another plugin query-string and props.location. Thanks for the suggestion!Juanjuana

© 2022 - 2024 — McMap. All rights reserved.