State Management 5.12_Refactoring


Refactoring


分離コードはgirly factoringと呼ばれます.
前のToDoList
Create ToDoとToDoListとToDoに分かれています
この場合atomを使うべきで、
toDoStateをatomに移動します.インタフェースとともに...出口も少ないです.


ToDoList.tsx

import React from "react";
import { useForm } from "react-hook-form";

export default function ToDoList() {
    interface IForm {
        email: string;
        firstName: string;
        lastName: string;
        username: string;
        password: string;
        passwordConfirm: string;
        extraError?: string;
    }

    const {
        register,
        handleSubmit,
        formState: { errors },
        setError,
    } = useForm<IForm>({
        defaultValues: {
            email: "@naver.com",
        },
    });

    const onValid = (data: IForm) => {
        if (data.password !== data.passwordConfirm) {
            setError("passwordConfirm", { message: "Password is not same" });
        }
        // setError("extraError", { message: "server offline" }, { shouldFocus: true });
    };
    console.log(errors);

    return (
        <div>
            <form style={{ display: "flex", flexDirection: "column" }} onSubmit={handleSubmit(onValid)}>
                <input
                    {...register("email", {
                        required: "email is required",
                        pattern: {
                            value: /^[A-Za-z0-9._%+-][email protected]$/,
                            // ^ :문장의 시작
                            // [] : 문자셋 안의 아무문자
                            // + : 하나 또는 많이
                            message: "Only naver.com emails allowed",
                        },
                    })}
                    placeholder="Email"
                />
                <input
                    {...register("firstName", {
                        required: true,
                        minLength: 3,
                        validate: {
                            NoEugene: (value) => (value.includes("eugene") ? "No Eugene allowed" : true),
                            NoEugenius: (value) => (value.includes("eugeniusS") ? "No Eugene allowed" : true),
                        },
                    })}
                    placeholder="First Name"
                />
                <span>{errors.firstName?.message}</span>
                <input
                    {...register("lastName", {
                        required: true,
                        minLength: {
                            value: 5,
                            message: "Your password is too short",
                        },
                    })}
                    placeholder="Last Name"
                />
                <span>{errors?.lastName?.message}</span>
                <span>{errors?.email?.message}</span>
                <input {...register("password", { required: true })} placeholder="Password" />
                <span>{errors?.password?.message}</span>
                <input {...register("passwordConfirm", { required: "Password is required" })} placeholder="Password Confirm" />
                <span>{errors?.passwordConfirm?.message}</span>
                <button>Add</button>S<span>{errors?.extraError?.message}</span>
            </form>
        </div>
    );
}

ToDo.tsx

import { createGlobalStyle } from "styled-components";
import ToDoList from "./components/07_Refactoring_ToDoList";

const GlobalStyle = createGlobalStyle`
  @import url('https://fonts.googleapis.com/css2?family=Archivo+Narrow:wght@500&family=Bebas+Neue&family=Black+Han+Sans&family=Do+Hyeon&family=Source+Sans+Pro:wght@300;400&family=Ubuntu+Mono:ital@1&display=swap');
  html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, menu, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
main, menu, nav, output, ruby, section, summary,
time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, main, menu, nav, section {
  display: block;
}
/* HTML5 hidden-attribute fix for newer browsers */
*[hidden] {
    display: none;
}
body {
  line-height: 1;
}
menu, ol, ul, li {
  list-style: none;

}
button{
  border: none;
  outline: none;
  background-color: transparent;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}
blockquote, q {
  quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
  content: '';
  content: none;
}
table {
  border-collapse: collapse;
  border-spacing: 0;
}
*{
  box-sizing: border-box;
}
body{
  font-family: 'Source Sans Pro', sans-serif;

}
a{
  text-decoration: none;
  color:inherit;
}
  `;

export default function App() {
    return (
        <>
            <GlobalStyle />
            <ToDoList />
        </>
    );
}

CreateToDo.tsx

import { useForm } from "react-hook-form";
import { useSetRecoilState } from "recoil";
import { toDoState } from "../../../atoms";

interface IForm {
    toDo: string;
}

function CreateToDo() {
    const setToDos = useSetRecoilState(toDoState);
    const { register, handleSubmit, setValue } = useForm<IForm>();
    const handleValid = ({ toDo }: IForm) => {
        setToDos((oldToDos) => [{ text: toDo, id: Date.now(), category: "TO_DO" }, ...oldToDos]);
        setValue("toDo", "");
    };
    return (
        <form onSubmit={handleSubmit(handleValid)}>
            <input
                {...register("toDo", {
                    required: "Please write a To Do",
                })}
                placeholder="Write a to do"
            />
            <button>Add</button>
        </form>
    );
}

export default CreateToDo;

atoms.tsx

import { atom } from "recoil";

export interface IToDo {
    text: string;
    id: number;
    category: "TO_DO" | "DOING" | "DONE"; //string;
    //위 문자열만 받도록 제한한다.
}

export const toDoState = atom<IToDo[]>({
    //atom 타입이 toDo의 배열임을 알려준다.
    key: "toDo",
    default: [],
});