[ReactJS_MasterClass] #6 STATE MANAGEMENT (1)

유은선·2023년 2월 1일
0

ReactJS_MasterClass

목록 보기
6/11
post-thumbnail

✍6.0 Dark Mode part One

Recoil은 React JS에서 사용할 수 있는 state management library
state management가 무엇인지 알아보기 위해, state management를 사용하지 않고 일단 기능을 구현해보자.

state를 사용하기 위해 index에서 App으로 ThemeProvider를 옮겨서 수정할 수 있도록 구현

✍6.1 Dark Mode part Two

✔️1. toggleDark 함수는 App 내에 있고, Coins는 Router 안에 있으므로 function을 Router로 보내야한다. (App → Router)

//App.tsx
const toggleDark = () => setIsDark((current) => !current);
<Router toggleDark={toggleDark} />

//Router.tsx
interface IRouterProps {
  toggleDark: () => void;
}
function Router({ toggleDark }: IRouterProps) {}

✔️2. toogleDark를 Coins screen으로 주어야한다. (Router → Coins)

//Router.tsx
<Route path="/" element={<Coins toggleDark={toggleDark} />} />

//Coins.tsx
interface ICoinsProps {
  toggleDark: () => void;
}
function Coins({ toggleDark }: ICoinsProps) {
	<button onClick={toggleDark}>Toggle Mode</button>
}

그리고 isDark를 Chart까지 전달하기 위해 App→Router→Coin→Chart 까지 복잡한 과정을 거친다. 이 경우, 다른 screen들의 다른 component들에서 같은 state에 접근하고 수정도 할 수 있었어야 했다. 좋은 해결책이 아님!😥

App (isDark, toggleDark)
→ Router → Coins (toggleDark)
→ Router → Coin → Chart (isDark)

global state는 어플리케이션이 전체에서 공유되는 state이다. 특정 value에 접근해야 할 때 쓰는 것
예를 들어 로그인 정보는 많은 component가 필요로 할 수 있는데 지금까지 한 방식의 React State를 사용한다면 복잡한 과정을 거칠 수 밖에 없다. 이러한 이유로 state management가 필요한 것!

✍6.2 Introduction to Recoil

이번 챕터에서는
component를 어떻게 atom의 value로 연결하는지
에 대해서 알아보자.
https://recoiljs.org/ko/
Recoil을 쓰면 Chart 나 App 과 같이 value 가 필요한 component에서만 value를 가질 수 있도록 한다.

부모에서 자식으로 prop을 계속 전달하는 대신에 atom을 생성해서 전달하면 된다.

npm install recoil

index.tsx에서 RecoilRoot로 App을 감싸주기만 하면 준비 끝

//index.tsx
<RecoilRoot>
      <QueryClientProvider client={queryClient}>
        <App />
      </QueryClientProvider>
</RecoilRoot>

atom은 두가지를 요구하는데, key와 default를 필요로 한다.

//atoms.ts
import { atom } from "recoil";

export const isDarkAtom = atom({
  key: "isDark",
  default: "false",
});

✍6.3 Introduction to Recoil part Two

useSetRecoilState를 쓰면 atom의 value를 수정할 수 있다!

//Coins.tsx
const setDarkAtom = useSetRecoilState(isDarkAtom);
const toggleDarkAtom = () => setDarkAtom((prev) => !prev);

✍6.4 Recap

useRecoilValue : atom의 값을 얻는 함수
useSetRecoilState : 매개 변수로 atom을 받고, atom을 변경하는 함수를 반환

예를들어 App이나 Chart 컴포넌트에서 atom의 값을 관찰하기 시작하고 atom이 변경되면 컴포넌트도 변경된 값으로 다시 리렌더링 될 것이다.

✍6.5 To Do Setup

App, index, theme을 제외하고 다른 파일들을 지워서 세팅
input을 state로 관리하고, onChange 이벤트로 업데이트한다. 만약 input이 3개가 있다면 각각을 관리하는 함수를 그만큼 만들어야 하는데(user name, email 각각에 대한) 다음 챕터에서는 이 코드를 한 줄의 코드로 작성하는 방법을 알아보도록 하자🤣

const onChange = (event: React.FormEvent<HTMLInputElement>) => {
    const {
      currentTarget: { value },
    } = event;
    setToDo(value);
  };
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    console.log(toDo);
  };
  
<form onSubmit={onSubmit}>
	<input onChange={onChange} value={toDo} placeholder="Write a to do" />
	<button>Add</button>
</form>

✍6.6 Forms

react-hook-from은 리액트에서 form으로 작업하기에 좋은 방법이며, 큰 form을 가지거나 form 검증이 많을 때 특히 유용하다.

react-hook-form 설치

npm install react-hook-form

{...register("toDo")}는 register 함수가 반환하는 객체를 가져다가 input에 props로 주는 것이다.
따라서 useForm을 사용한 한줄의 코드가 onChange 이벤트와 value, setState를 대체 한 것!

또한 useForm은 form의 입력값들의 변화를 관찰 할 수 있게 해주는 함수 인watch도 제공한다.

정리해보자면, register로 onChange 이벤트 함수를 만들고, input에 props로 줄수 있으며 watch로 form의 입력값을 추적할 수 있다.

<form>
        <input {...register("email")} placeholder="Email" />
        <input {...register("firstName")} placeholder="First Name" />
        <input {...register("lastName")} placeholder="Last Name" />
        <input {...register("username")} placeholder="Username" />
        <input {...register("password1")} placeholder="Password1" />
        <input {...register("password2")} placeholder="Password2" />
        <button>Add</button>
      </form>

✍6.7 Form Validation

onSubmit 이벤트안에 handleSubmit 을 호출하고, handleSubmit은 두개의 인자를 받는다. 하나는 데이터가 유효할 때 호출되는 함수(onValid)이고, 다른 하나는 데이터가 유효하지 않을 때 호출되는 함수(onInValid)이다. onValid는 필수!

데이터의 validation이 해결됐으며, 에러가 어디서 발생했는지도 알 수 있다.

const { register, handleSubmit, formState } = useForm();

<input {...register("password2", {
	required: "Password is required",
    minLength: {
      value: 5,
      message: "Your password is too short",
   },
  })}
 placeholder="Password2"/>

✍6.8 Form Errors

정규식을(RegExp)을 사용한 또 다른 validation 방법을 알아보자.

<input {...register("email", {
		required: "Email is required",
		pattern: {
			value: /^[A-Za-z0-9._%+-]+@naver.com$/,
			message: "Only naver.com emails allowed",
            },
          })}
       placeholder="Email" />

✍6.9 Custom Validation

어떤 경우에는 서버에서 문제가 발생해서 에러를 발생시켜야 할 경우도 있는데, 지금까지 배운 검사 방법 이외의 validation 방법이 있는지 알아보자.

✔️setError는 특정한 에러를 발생시키도록 도와준다.

누군가 서버를 해킹해서 서버가 다운되어 접속이 끊긴경우를 예로 들어보자.우리가 만든 setError를 보면, IForm에 있는 옵션들만 나오는데 form interface에 extraError를 만들어 특정한 항목에 해당되는 에러가 아닌 전체 form에 해당되는 에러를 보여주도록 한다.

setError에서 또 유용한 점 하나는, form 에서 내가 고른 input 항목에 강제로 focus 시킬수 있는 것이다.

 setError(
        "password2",
        { message: "Password ar not the same" },
        { shouldFocus: true }
      );

✔️validate는 함수를 값으로 가지는데, 이 함수는 인자로 항목에 현재 쓰여지고 있는 값을 받으며, true 또는 false를 반환한다.
또한 react-hook-form에서 문자열을 리턴하면 즉 에러 메세지를 리턴한다는 뜻이 되므로 validate에서도 문자열을 리턴하면 에러 메세지가 되는 것이다.

 validate: (value) => value.includes("tony") ? "no tony allowed" : true

✔️그리고 validate는 하나의 함수 또는 여러 함수가 있는 객체가 될 수 있는데, input에 여러 개의 검사가 필요할 수도 있기 때문이다.

 validate: {
	noTony: (value) => value.includes("tony") ? "no tony allowed" : true,
	noKang: (value) => value.includes("kang") ? "no kang allowed" : true,
}

✍6.10 Recap

shouldFocus 는 사용자가 form을 submit 할 때 에러를 발생시키면 커서를 해당 input에 focus 시켜준다.

입력값이 submit이 되고, 값이 검사를 통과하면 다시 input을 비우기 위해 setValue를 이용한다.

const { register, handleSubmit, setValue } = useForm<IForm>();
const onSubmit = (data: IForm) => {
    console.log("add to do", data.toDo);
    setValue("toDo", ""); //유효하다면 submit이 된 뒤 문자열이 비워진다.
  };
profile
뭐든지 난 열심히 하지

0개의 댓글