3
\$\begingroup\$

I am really new to React and I worked on some challenges. I need to mention I did most of the stuff on my own without much dependence on the internet beside what functions do. I'd like to know if I did something wrong in regard to code structure and if there are better ways to achieve what I did.

The purpose of the code is a simple registration form with validation, step by step. At the end, it will complete and a heading will be displayed.

App:

import "./App.css";
import Card from "./Card";
import React, { useState } from "react";
import UserInput from "./UserInput";

function App() {
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [email, setEmail] = useState("");
  const [step, setStep] = useState(1);
  const [error, setError] = useState(true);
  const onFirstNameChange = (event) => {
    setFirstName(event.target.value);
  };
  const onLastNameChange = (event) => {
    setLastName(event.target.value);
  };
  const onEmailChange = (event) => {
    
    setEmail(event.target.value);
    
  };
  const onSubmitHandler = (event) => {
    event.preventDefault();
    if (step === 1 && firstName.trim().length === 0) {
      setError(false);
      return;
    }
    if (step === 2 && lastName.trim().length === 0) {
      setError(false);
      return;
    }
    if (step === 3 && email.trim().length === 0) {
      setError(false);
      return;
    }
    setStep((prevValue) => {
      return prevValue + 1;
    });
  };
  const stepBack = () => {
    if (step === 2 && firstName.trim().length !== 0) {
      setError(true);
      setStep((prevValue) => {
        return prevValue - 1;
      });
    }
    if (step === 3 && lastName.trim().length !== 0) {
      setError(true);
      setStep((prevValue) => {
        return prevValue - 1;
      });
    }
    if (!error) return;
  };
  if(step===4){
    return <h2>Registration Completed !</h2>
  }
  return (
    <React.Fragment>
      <Card>
        <UserInput
          submitHandler={onSubmitHandler}
          onEmailChange={onEmailChange}
          onFirstNameChange={onFirstNameChange}
          onLastNameChange={onLastNameChange}
          stepNum={step}
          value={step === 1 ? firstName : step === 2 ? lastName : email}
        ></UserInput>
        {step > 1 && <button onClick={stepBack}>Back</button>}
        {!error && <label style={{ color: "red" }}> Required !</label>}
      </Card>
      <Card>
        <p>{firstName}</p>
        <p>{lastName}</p>
        <p>{email}</p>
      </Card>
    </React.Fragment>
  );
}

export default App;

UserInput:

import React from "react";

const UserInput = (props) => {
  const firstNameHolder = (
    <React.Fragment>
      <label>First Name</label>
      <br />
      <input
        id="firstName"
        type="text"
        onChange={props.onFirstNameChange}
        value={props.value}
      ></input>
    </React.Fragment>
  );
  const lastNameHolder = (
    <React.Fragment>
      <label>Last Name</label>
      <br />
      <input
        id="lastName"
        type="text"
        onChange={props.onLastNameChange}
        value={props.value}
      ></input>
    </React.Fragment>
  );
  const emailHolder = (
    <React.Fragment>
      <label>Email</label>
      <br />
      <input
        id="email"
        type="email"
        onChange={props.onEmailChange}
        value={props.value}
      ></input>
    </React.Fragment>
  );
  return (
    <React.Fragment>
      <form onSubmit={props.submitHandler}>
        {props.stepNum === 1 && firstNameHolder}
        {props.stepNum === 2 && lastNameHolder}
        {props.stepNum === 3 && emailHolder}
        <button type="submit">Next</button>
      </form>
    </React.Fragment>
  );
};

export default UserInput;

Card

import React from "react";
import styles from './Card.module.css';

const Card = (props) => {
  return <div className={`${styles.card} ${props.className}`}>{props.children}</div>;
};

export default Card;

Card.module.css

.card{
    position: center;
    padding: 2em;
    margin: 2em;
    background: white;
    box-shadow: 0 2px 8px black;
    border-radius: 10px;
}
\$\endgroup\$
0
1
\$\begingroup\$

you can make this part of code a little bit shorter, before:

const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [email, setEmail] = useState("");

const onFirstNameChange = (event) => {
    setFirstName(event.target.value);
  };
  const onLastNameChange = (event) => {
    setLastName(event.target.value);
  };
  const onEmailChange = (event) => {
    
    setEmail(event.target.value);
    
  };

after:

const initialForm = {
  firstName: '',
  lastName: '',
  email: ''
}
...
const [form, setForm] = useState(initialForm );

// allways wrap your components functions inside useCallback, to save it's value after rerender
const formChangeHandler = useCallback((event) => {
  // use "prev" param, to make dependences array empty
  setForm((prev) => (
    [event.target.name]: event.target.value
  ));
}, [])

better to use switch/case structure here, and rename numbers to some words, you will get some problems if you will need to add some inputs between 1 and 2

{props.stepNum === 1 && firstNameHolder}
{props.stepNum === 2 && lastNameHolder}
{props.stepNum === 3 && emailHolder}

for this functions is better to create custom inputField component. Before:

const emailHolder = (
    <React.Fragment>
      <label>Email</label>
      <br />
      <input
        id="email"
// by the way - don't use email type for input. It had some problems
        type="email"
        onChange={props.onEmailChange}
        value={props.value}
      ></input>
    </React.Fragment>
  );

after:

const InputFieldComponent = ({ label, name, type, onChange, value }) => (
    <React.Fragment>
      <label>{label}</label>
      <br />
      <input
        id={name}
        type={type}
        onChange={onChange}
        value={value}
      ></input>
    </React.Fragment>
)

// and inside ur render

return (
  <InputFieldComponent
    label="Email"
    name="email"
    type="text"
    onChange={formChangeHandler}
    value={form.email}
  />
  <InputFieldComponent
    label="Email"
    name="email"
    type="text"
    onChange={formChangeHandler}
    value={form.email}
  />
)
```
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.