클릭한 내용을 로컬스토리지 장바구니에 담는다. 백엔드는 로그인을 하지 않았기 때문에 누구인지 알 수 없으니, 자기 자신 컴퓨터의 로컬스토리지에 담는다.
빈 배열 basket에 클릭한 내용을 담고 로컬스토리지에 setItem
을 이용하여 저장한다. 그러나 이대로 저장하면 문제가 발생한다. 배열이나 객체는 localStorage, sessionStorage에는 문자열 밖에 못 들어가기 때문에 JSON.stringify(baskets)
를 이용하여 문자열로 바뀐 뒤 저장시킨다.
이렇게하면, 장바구니에 데이터를 저장할 때마다 빈 배열에 저장되므로 기존의 값들이 사라진다. 이 문제를 해결하기 위해 localStorage에서 기존의 장바구니를 가지고 온다. 만약 기존의 장바구니가 없으면 빈 배열을 만들어서 가지고 온다. localStorage에서 가져왔기 때문에 문자열이므로 다시 JSON.parse(...)
로 배열형태로 변환시켜 가져온다.
이렇게해서 장바구니에 상품을 담고 가지고 오는 부분까지 완료하였으나, 클릭하면 매번 푸시가 되기 때문에 매번 담았던 것을 계속 담게되는 문제가 생긴다. 그래서 한번 담았던 것은 빼도록 한다. 그렇게 하기 위해 filter
를 이용하여 담은 물품의 id와 기존 장바구니 안의 물품의 id와 비교하여 있다면 alert을 띄우고 return 하여 해당 물품에 장바구니에 담기는 것을 skip한다.
왜 데이터를 로컬스토리지에 저장할까?
기획 의도에 적합한 저장소를 선택
하면 된다.만약 로그인을 한다면?
만약 내 장바구니 보기를 하려면?
1. 내 장바구니 보기 페이지를 만드려면, localStorage에 저장한 데이터를 가지고 와서 state에 넣어준다.
2. 프론트엔드 서버에서 프리렌더링이 이루어질 때에는 localStorage가 존재하지 안히 때문에 오류가 발생한다.
-> useEffect
를 사용하여 브라우저에서 페이지가 마운트 될 때에만 해당 코드를 실행시킨다.
3. 로컬 스토리지에 넣은 데이터를 넣은 state를 map을 이용하여 화면에 뿌려주면 된다.
react-hook-form
비제어 컴포넌트 : 바닐라 자바스크립트 처럼 sumit함수를 실행할 때 ref 로 input값을 한번에 변경합니다. onChange가 일어나지 않는다.
제어 컴포넌트 : 사용자의 입력을 기반으로 state를 실시간으로 관리(setState 사용). 쉽게 말해 입력이 될 때마다 state값이 실시간으로 변경됩니다.
제어 컴포넌트는 버튼색 바꾸는 isActive 경우 제어컴포넌트를 활용하여 입력할 때마다 state를 업데이트 해주고 변경을 체크해야 하기 때문에 제어 컴포넌트를 사용한다.
이전까지는 제어 컴포넌트 방식이였으나, react-hook-form은 비제어 컴포넌트 방식으로 입력할 때마다 state가 바뀌지 않아 리렌더링 없이 사용하여 성능이 빠르다.
게시글처럼 많은 양의 입력값이 있어서, 입력할 때마다 렌더링이 일어나기 때문에 데이터가 큰, 텍스트가 많은 데이터 사용시 성능이 느려지기 때문에 비제어 컴포넌트가 효율적이다.
그러나 react-hook-fomr은 비제어 컴포넌트이기 때문에 한번만 렌더해서 보내기 때문에 정확성이 떨어진다.
따라서 중요한 데이터를 입력받는 페이지는 제어 컴포넌트를 사용해 변경사항에 대한 정확도를 높여주시는게 좋다.
form 태그는 input에 적힌 내용을 전송해주는 기능이 있다.
react-hook-form 에서는 이 기능을 이용한다.
button 태그의 type에 reset을 주게 되면 클릭시에 폼 안에 있는 인풋값을 초기화 한다.
submit을 주시게 되면 form태그에 바인딩된 submit 함수를 실행시키게 된다.
버튼 타입의 기본은 submit이다. 따라서 폼안에서 사용하게 되면, 따로 명시 하지 않아도 submit의 기능을 하게 된다.
만일 form 태그 내에서 form과 상관없는 버튼을 만들어야 한다 하면, type을 button으로 해야 한다.
form 내부의 button type 간단 정리
reset : form 내부의 input 값이 모두 삭제 된다.
submit : form 내부의 input 값이 백엔드로 보내진다. → 기본값
button : 나만의 버튼을 만들고 싶을때 사용한다.
React-hook-form을 사용한 작성은 ajax(비동기 javascript통신)으로 지금까지 만들었던 방식과는 조금 다르다.
먼저 입력값을 받을 Input태그들을 form이라는 태그로 감싸준다.
그리고 변경되는 input에 대한 처리는 useForm()으로 state를 등록
하는데 필요한 모든 기능(onChange,onClick, onError 등)이 담겨있는 register를 가져와 input에 스프레드
시켜준다.
스프레드를 시켜주며 register(“”)안에 input의 이름, 즉 state변수명도 넣어준다.
이렇게 담긴 값들은 formState에 담는다!
최상단에 감싸진 form 태그에는 onSubmit()이라는 함수를 연결 시켜주었고, 이렇게 연결해준 onSubmit이 작동될 수 있로고 form 태그 내부에 button태그를 넣어주어 버튼을 누르면 onSubmit에 담은 함수가 실행이 되도록 한다.
(버튼의 default type은 submit이기 때문에 다른 기능이 들어간 버튼을 만들어 추가적으로 넣어줄 때는 type을 button
으로 주어 사용해야 한다)
그리고 여기서 중요한 것은 onSubmit에 만든 함수를 넣어줄때는 등록한 데이터를 담아서 실행해야하기 때문에, hook-form에서 제공하는 handleSubmit
으로 감싸서 실행해야 합니다.
button 등록하기를 누르게 되면 button 타입의 default는 submit이기 때문에 form 태그의 onSubmit이 실행되는데 onClickSubmit 함수를 실행하게 된다.
button 등록하기를 눌렀을 때 다른 함수를 실행시키고 싶다면 button 태그의 type 속성을 'button'
으로 변경해주고 onClick 속성을 추가해야 한다.
{...register('writer')}
태그를 추가한다.
비제어 컴포넌트이기 때문에 입력할 때마다 writer state에 저장되지 않고 handleSubmit
이 onClickSubmit으로 입력한 register의 state로 writer, title, contents를 전달해준다.
form 라이브러리를 사용하여 함수도 하나만 만들고 state도 안 만들어도 되기 때문에 효율적이다.
register, handleSubmit, form
register : state를 등록하는데 필요한 모든 기능이 들어있다.
handleSubmit : resister에 적힌 state를 등록해주는 함수 이다.
form : 실제 html에 있는 input들을 묶어주는 태그이다.
전체코드
import { useForm } from "react-hook-form";
export default function ReactHookFormPage() {
const { register, handleSubmit } = useForm();
// 등록하기 함수 -> handleSubmit이 조종해주는 함수 입니다.
const onClickSubmit = (data)=>{
console.log(data)
}
return(
<form onSubmit={handleSubmit(onClickSubmit)}>
<input type="text" {...register("writer")}/>
<input type="text" {...register("title")}/>
<input type="text" {...register("contents")}/>
<button type="reset"> 등록하기 </button>
</form>
)
}
import * as yup from 'yup'
import {useForm} from 'react-hook-form'
import {yupResolver} from '@hookform/resolvers/yup'
// yup 에러메세지 생성해주기 -> 제어 컴포넌트 형태로 사용해야 합니다.
const schema = yup.object().shape({
myWriter : yup
.string()
.email('이메일 형식이 적합하지 않습니다.')
.required('필수 입력값입니다.'),
myPassword : yup
.string()
.min(4,'비밀번호는 최소 4자리 이상입니다.')
.max(15,'비밀번호는 최대15자리 입니다.')
.required('필수 입력값 입니다.')
})
const {register , handleSubmit, formState} = useForm({
// schema는 위에서 만들어 둔 schema입니다.
resolver : yupResolver(schema),
mode : "onChange"
})
mode: 'onChange'
를 추가하여 변경할 때마다 검증을 하여 리렌더링 시켜준다.yup에 정규표현식 추가하기
yup.string().matches(/ 원하는 정규표현식! /)
schema란?
→ 구조를 의미
보통 하나의 구조를 schema라고 하는데 만들어둔 하나의 yup을 schema라고 하기로 한다.
Pick
을 이용하여 사용하고자 하는 타입만 사용하였다.Omit
을 이용하여 빼는 것이 효율적이다.개발자 도구 - Application
에 들어가서 localStorage에 들어온 것을 확인할 수 있다.button type='reset'
은 폼 안에 있는 input들을 초기화시켜줘!
input이 지워진다고 state가 지워지는 것은 아니다.
button type='submit'
은 form onSubmit={백엔드 api주소}
로 자동으로 input 안의 데이터들이 날아간다.
button type='button'
으로 해야 onClick~ 을 적용할 수 있다.
form으로 감싸게 되면 button 태그의 default는 type='submit'
이 되기 때문에 주의해야 한다.