Victor M
Victor M

Reputation: 749

React function component state not re-rendering?

I am currently trying to make a login/signup form whose components will render differently depending on if the user toggles "Log In" or "Sign In" (see ColorToggleButton). I used a React hook whose parameters I pass to the different function components to change their state. On initial rendering, the "Log In" settings show; however, when pressing "Sign In", it seems only LogInOrSignIn changes rendering to the sign in components. Furthermore, any further toggling doesn't change any rendering after that.

import React, { useState, useEffect } from 'react';
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import CssBaseline from '@mui/material/CssBaseline';
import TextField from '@mui/material/TextField';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import Link from '@mui/material/Link';
import Grid from '@mui/material/Grid';
import Box from '@mui/material/Box';
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
import Typography from '@mui/material/Typography';
import Container from '@mui/material/Container';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';


function Copyright(props) {
  return (
    <Typography variant="body2" color="text.secondary" align="center" {...props}>
      {'Copyright © '}
      <Link color="inherit" href="https://mui.com/">
        Your Website
      </Link>{' '}
      {new Date().getFullYear()}
      {'.'}
    </Typography>
  );
}


function ColorToggleButton(props) {
    const handleChange = (event) => {
      props.toggle(event.value)
    };
  
    return (
      <>
      <ToggleButtonGroup
        color="primary"
        value={props.status}
        exclusive
        onChange={handleChange}
      >
        <ToggleButton value="login">Log In</ToggleButton>
        <ToggleButton value="signin">Sign In</ToggleButton>
      </ToggleButtonGroup>
      </>
    );
  }

function SubmitButton(props) {
    let buttonText;
    if (props.status === "signin") {
        buttonText = "Sign Up"
    } else {
        buttonText = "Log In"
    }
    return (
        <Button
              type="submit"
              fullWidth
              variant="contained"
              sx={{ mt: 3, mb: 2 }}
            >
              {buttonText}
        </Button>
    )
}

function LogInOrSignIn(props) {
    if (props.status === "login") {
        return (
            <>
            <TextField
              margin="normal"
              required
              fullWidth
              id="email"
              label="Email/Username"
              name="email"
              autoComplete="email"
              autoFocus
            />
            <TextField
              margin="normal"
              required
              fullWidth
              name="password"
              label="Password"
              type="password"
              id="password"
              autoComplete="current-password"
            />
            </>
        )
    }

    return (
        <>
        <TextField
          margin="normal"
          required
          fullWidth
          id="username"
          label="Username"
          name="username"
          autoComplete="email"
          autoFocus
        />
        <TextField
          margin="normal"
          required
          fullWidth
          id="email"
          label="Email"
          name="email"
          autoComplete="email"
          autoFocus
        />
          <TextField
          margin="normal"
          required
          fullWidth
          name="password"
          label="Password"
          type="password"
          id="password"
          autoComplete="current-password"
        />
        </>
    )
}

function ForgotPassword(props) {
    if (props.status === "signin") {
        return null;
    }
    return (
        <>
        <Grid container>
              <Grid item xs>
                <Link href="#" variant="body2">
                  Forgot password?
                </Link>
              </Grid>
        </Grid>
        </>
    )
}

const theme = createTheme();

function LogIn() {
  const [userStatusContext, setState] = useState("login");
  const handleSubmit = (event) => {
    event.preventDefault();
    const data = new FormData(event.currentTarget);
    // eslint-disable-next-line no-console
    console.log({
      email: data.get('email'),
      password: data.get('password'),
    });
  };

  return (
    <ThemeProvider theme={theme}>
      <Container component="main" maxWidth="xs">
        <CssBaseline />
        <Box
          sx={{
            marginTop: 8,
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'center',
          }}
        >
          <Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
            <LockOutlinedIcon />
          </Avatar>
          <ColorToggleButton toggle={setState} status={userStatusContext}/>
          <Typography component="h1" variant="h5">
            Sign in
          </Typography>
          <Box component="form" onSubmit={handleSubmit} noValidate sx={{ mt: 1 }}>
            <LogInOrSignIn status={userStatusContext}/>
            <SubmitButton status={userStatusContext}/>
          </Box>
          <ForgotPassword status={userStatusContext}/>
        </Box>
        <Copyright sx={{ mt: 8, mb: 4 }} />
      </Container>
    </ThemeProvider>
  );
}

export default LogIn;

I'm not really sure what's going on. I had thought React would re-render all affected function components that depend on the state hook that I use, if it changes. Any advice would be much appreciated.

Upvotes: 0

Views: 240

Answers (1)

Jerry
Jerry

Reputation: 198

the problem is in function ColorToggleButton(props). you did not pass the toggle value to parent component. also you do not need to pass the value as a prop to ColorToggleButton.

    function ColorToggleButton(props) {
const [value, setValue] = useState("login")
        const handleChange = (event) => {
          setValue(event.value);
props.toggle(event.value);
        };
      
        return (
          <>
          <ToggleButtonGroup
            ...
            value={value}
            ...

function Login(){
<ColorToggleButton toggle={(value)=>setState(value)} />
}

this is the rough idea and did not check my code. you can give it a go.

Upvotes: 1

Related Questions