Search code examples
javascriptreactjsreact-reduxreact-hooksuse-effect

I am passing the state to a function component via history (react-router-dom) but it says the state is 'null'


I need to pass the state value to a different component and I want to use it in the different component.

for the same problem, I have asked a different question which was closed as duplicate however, I have tried everything mentioned in the previous question. I do not think this is a duplicate question.

This is the some of the code in the first component:

    const handleFormSubmit = async (event) => {
        event.preventDefault()
        console.log(formData)
        try {
            await axios
                .post(`http://localhost:4000/accounts/register`, formData)
                .then(function (response) {
                    console.log(response)
                    console.log(response.data)
                    const newValue = response.data
                    setServerMessage(newValue)
                })
        } catch (error) {
            console.log(error)
        }
        history({
            pathname: '/session/verifyotp',
            state: { serverMessage: serverMessage },
        })
    }
    useEffect(() => {
        if (serverMessage) {
            console.log(serverMessage)
            setServerMessage(serverMessage)
            console.log(serverMessage)
        }
    }, [serverMessage])

The code in the second component where I am trying to access the state.

const navigate = useNavigate()
let data = useLocation()
console.log(data)

This is the complete code in the first page :

import React, { useEffect, useState } from 'react'
import { Box, styled } from '@mui/system'
import { Grid, Button } from '@mui/material'
import { ValidatorForm, TextValidator } from 'react-material-ui-form-validator'
import Typography from '@mui/material/Typography'
import { FormLabel } from '@mui/material'
import Link from '@mui/material/Link'
import axios from 'axios'
import Appbar from '../Appbar'
import Alert from '@mui/material/Alert'
import Snackbar from '@mui/material/Snackbar'
import { useNavigate } from 'react-router-dom'

const FlexBox = styled(Box)(() => ({
    display: 'flex',
    alignItems: 'center',
}))

const JustifyBox = styled(FlexBox)(() => ({
    justifyContent: 'center',
}))

const IMG = styled('img')(() => ({
    width: '100%',
}))

const JWTRegister = styled(JustifyBox)(() => ({
    background: '#ffffff',
    minHeight: '100vh !important',
    input: {
        background: 'white',
        borderRadius: 25,
    },
}))

const JwtRegister = (props) => {
    const [serverMessage, setServerMessage] = useState('')
    const [open, setOpen] = useState(false)
    const history = useNavigate()

    const [formData, setFormData] = useState({
        name: '',
        mobile: '',
        email: '',
        password: '',
    })

    const handleClick = () => {
        setOpen(true)
    }

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

        setOpen(false)
    }
    const { name, mobile, email, password } = formData

    const handleChange = (event) => {
        setFormData({
            ...formData,
            [event.target.name]: event.target.value,
        })
    }

    const handleFormSubmit = async (event) => {
        event.preventDefault()
        console.log(formData)
        try {
            await axios
                .post(`http://localhost:4000/accounts/register`, formData)
                .then(function (response) {
                    console.log(response)
                    console.log(response.data)
                    const newValue = response.data
                    setServerMessage(newValue)
                })
        } catch (error) {
            console.log(error)
        }
        history({
            pathname: '/session/verifyotp',
            state: { serverMessage: serverMessage },
        })
    }
    useEffect(() => {
        if (serverMessage) {
            console.log(serverMessage)
            setServerMessage(serverMessage)
            console.log(serverMessage)
        }
    }, [serverMessage])
    return (
        <JWTRegister>
            <Grid container>
                <Appbar />
                <Grid
                    pt={0}
                    pl={10}
                    pr={10}
                    item
                    lg={6}
                    md={6}
                    sm={6}
                    xs={12}
                    sx={{ height: '100vh', backgroundColor: '#3E8BFF' }}
                >
                    <Typography
                        component="h1"
                        variant="h3"
                        sx={{ textTransform: 'none', color: '#000' }}
                    >
                        Sign up
                    </Typography>
                    <Typography component="h1" variant="h5">
                        Register now to get 100 free credits
                    </Typography>
                    {serverMessage ? (
                        <>
                            <Alert
                                variant="filled"
                                autohideduration={6000}
                                severity="success"
                            >
                                {serverMessage.message}
                            </Alert>
                            <Snackbar
                                open={open}
                                autoHideDuration={3000}
                                onClose={handleClose}
                            >
                                <Alert
                                    onClose={handleClose}
                                    severity="success"
                                    sx={{ width: '100%' }}
                                >
                                    {serverMessage.message}
                                </Alert>
                            </Snackbar>
                        </>
                    ) : null}
                    <ValidatorForm id="Register" onSubmit={handleFormSubmit}>
                        <Grid container spacing={2}>
                            <Grid
                                item
                                lg={6}
                                md={6}
                                sm={12}
                                xs={12}
                                sx={{ mt: 2 }}
                            >
                                <FormLabel sx={{ color: '#000000' }}>
                                    Name
                                </FormLabel>
                                <TextValidator
                                    sx={{ mb: 3, width: '100%' }}
                                    size="small"
                                    type="text"
                                    name="name"
                                    value={name}
                                    autoFocus
                                    onChange={handleChange}
                                    validators={['required']}
                                    errorMessages={['Name field is required']}
                                    inputProps={{
                                        style: {
                                            borderRadius: 25,
                                            backgroundColor: 'white',
                                            disableUnderline: true,
                                        },
                                    }}
                                />
                            </Grid>
                            <Grid
                                item
                                lg={6}
                                md={6}
                                sm={12}
                                xs={12}
                                sx={{ mt: 2 }}
                            >
                                <FormLabel sx={{ color: '#000000' }}>
                                    Mobile
                                </FormLabel>
                                <TextValidator
                                    sx={{ mb: 3, width: '100%' }}
                                    size="small"
                                    type="text"
                                    name="mobile"
                                    value={mobile}
                                    onChange={handleChange}
                                    validators={['required']}
                                    errorMessages={[
                                        'Mobile Number field is required',
                                    ]}
                                    inputProps={{
                                        style: {
                                            borderRadius: 25,
                                            backgroundColor: 'white',
                                            disableUnderline: true,
                                        },
                                    }}
                                />
                            </Grid>
                        </Grid>
                        <FormLabel sx={{ color: '#000000' }}>Email</FormLabel>
                        <TextValidator
                            sx={{ mb: 3, width: '100%' }}
                            size="small"
                            type="email"
                            name="email"
                            value={email}
                            onChange={handleChange}
                            validators={['required', 'isEmail']}
                            inputProps={{
                                style: {
                                    borderRadius: 25,
                                    backgroundColor: 'white',
                                    disableUnderline: true,
                                },
                            }}
                            errorMessages={[
                                'Email field is required',
                                'Email is not valid',
                            ]}
                        />
                        <FormLabel sx={{ color: '#000000' }}>
                            Password
                        </FormLabel>
                        <TextValidator
                            sx={{ mb: '16px', width: '100%' }}
                            size="small"
                            name="password"
                            type="password"
                            value={password}
                            onChange={handleChange}
                            validators={['required']}
                            errorMessages={['Password field is required']}
                            inputProps={{
                                style: {
                                    borderRadius: 25,
                                    disableUnderline: true,
                                    backgroundColor: 'white',
                                },
                            }}
                        />
                        <FlexBox pb={2}>
                            <Button
                                type="submit"
                                variant="contained"
                                sx={{
                                    borderRadius: 25,
                                    textTransform: 'none',
                                    background: '#C7FF80',
                                    color: '#000000',
                                }}
                                onClick={handleClick}
                            >
                                Verify OTP
                            </Button>
                        </FlexBox>
                    </ValidatorForm>
                    <Typography
                        variant="subtitle1"
                        display="inline"
                        sx={{
                            textTransform: 'none',
                            color: '#000000',
                        }}
                    >
                        Already a member?
                        <Link
                            href="/session/signin"
                            sx={{
                                textTransform: 'none',
                                color: '#FFFFFF',
                            }}
                        >
                            &nbsp; Sign in &nbsp;
                        </Link>
                        instead.
                    </Typography>
                </Grid>
                <Grid
                    pt={1}
                    pl={10}
                    item
                    lg={6}
                    md={6}
                    sm={6}
                    xs={12}
                    sx={{ height: '100vh', backgroundColor: '#3E8BFF' }}
                >
                    <Typography pb={3} variant="body">
                        or sign up with
                    </Typography>
                    <Grid
                        pb={3}
                        pt={3}
                        container
                        alignItems="center"
                        spacing={2}
                    >
                        <Grid item>
                            <IMG
                                src="/assets/images/signup-linkedin.svg"
                                height={55}
                                width={55}
                            />
                        </Grid>
                        <Grid item>
                            <Typography pb={1} component="h6" variant="h6">
                                Linkedin
                            </Typography>
                        </Grid>
                    </Grid>
                    <Grid pb={3} container alignItems="center" spacing={2}>
                        <Grid item>
                            <IMG
                                src="/assets/images/signup-google.svg"
                                height={55}
                                width={55}
                            />
                        </Grid>
                        <Grid item>
                            <Typography pb={1} component="h6" variant="h6">
                                Google
                            </Typography>
                        </Grid>
                    </Grid>
                    <Grid pb={3} container alignItems="center" spacing={2}>
                        <Grid item>
                            <IMG
                                src="/assets/images/signup-facebook.svg"
                                height={55}
                                width={55}
                            />
                        </Grid>
                        <Grid item>
                            <Typography pb={1} component="h6" variant="h6">
                                Facebook
                            </Typography>
                        </Grid>
                    </Grid>
                    <Grid pb={3} container alignItems="center" spacing={2}>
                        <Grid item>
                            <IMG
                                src="/assets/images/signup-email.svg"
                                height={55}
                                width={55}
                            />
                        </Grid>
                        <Grid item>
                            <Typography component="h6" variant="h6">
                                Corporate Email ID
                            </Typography>
                            <span pb={1} component="h6" variant="h6">
                                (Use only Business email)
                            </span>
                        </Grid>
                    </Grid>
                </Grid>
            </Grid>
        </JWTRegister>
    )
}

export default JwtRegister

This is output I get in the second component:

Object { pathname: "/session/verifyotp", search: "", hash: "", state: null, key: "n1jhatdj" }

No matter what I try I am not able to pass the state to the different component. I have followed this question but does not solve my problem.

How can I access the state value? Why is it coming as null?

Edit:

after I made changes to the history like this:

        history('/session/verifyotp', {
            state: { serverMessage: serverMessage },
        })

I get the following output: serverMessage object is still empty :

hash: ""
​
key: "vi016u6e"
​
pathname: "/session/verifyotp"
​
search: ""
​
state: Object { serverMessage: "" }

Edited: My handleFormSubmit function

    const handleFormSubmit = async (event) => {
        event.preventDefault()
        console.log(formData)
        let newValue
        try {
            const response = await axios.post(
                `http://localhost:4000/accounts/register`,
                formData
            )
            console.log(response)
            console.log(response.data)
            newValue = response.data
            setServerMessage(newValue)
        } catch (error) {
            console.log(error)
        }
        history('/session/verifyotp', {
            state: { serverMessage: serverMessage },
        })
    }
    useEffect(() => {
        if (serverMessage) {
            console.log(serverMessage)
            console.log(serverMessage)
            setServerMessage(serverMessage)
        }
    }, [serverMessage])

error in browser console: enter image description here


Solution

  • You need to use your history like this for react-router v6.

    history("/session/verifyotp", {
      state: { serverMessage: serverMessage },
    });
    
    

    Check the Documentation. It accepts to and the state as an optional param.

    Here is my componentA

    import {useNavigate} from 'react-router-dom';
    
    const ComponentA = (props) => {
      const navigate = useNavigate();
      const toComponentB = () => {
        navigate("/componentB", { state: { id: 1, name: "sabaoon" } });
      };
      return (
        <button
          onClick={() => {
            toComponentB();
          }}
        >
          Component B
        </button>
      );
    };
    
    export default ComponentA;
    
    

    You can get the state data in componentB like this.

    import { useLocation } from "react-router-dom";
    
    function ComponentB() {
      const location = useLocation();
      return <div>{location?.state?.name}</div>;
    }
    
    export default ComponentB;
    
    

    You can update your handleFormSubmit method like this. You are using both async/await and .then which confuses the users.

    const handleFormSubmit = async (event) => {
      event.preventDefault();
      console.log(formData);
      let newValue;
      try {
        const response = await axios.post(
          `http://localhost:4000/accounts/register`,
          formData
        );
        console.log(response);
        console.log(response.data);
        newValue = response.data;
        setServerMessage(newValue);
      } catch (error) {
        console.log(error);
      }
      history({
        pathname: "/session/verifyotp",
        state: { serverMessage: newValue },
      });
    };