**데이터 - state에 저장하기
- useState
Hook 사용 이유
useEffect
useRef**
변수가 변경될 때 자동으로 HTML이 리렌더링되게 하려면, 변수에 말고 state에 데이터 바인딩해야한다.
예를 들어 D-day계산기에서 처럼 입력한 숫자에 따라 표시되는 날짜가 바뀌게 하고싶다
→ 수정될 때마다 스무스하게 변동사항이 반영되게하고싶다
→ 입력한 숫자, 표시되는 날짜 모두 state로 놓고 사용해야한다.
그렇다고 모든 데이터를 state로 바인딩하냐? - 바뀌지 않을 값들은 굳이 하지 않는다.
state는 변수처럼 그냥 재할당해서 변경하면 안됨. 특별한 방법을 써야함! 변수처럼 쓴다면 state쓰는 의미가 없음..
특별한방법? useState함수 사용하기! (class컴포넌트라면 setState...)
import React, {useState} from 'react';
function Example() {
const [like, setLike] = useState(기본값); //destructuring
}
return (
export default Example;
like는 state, setLike는 like라는 state를 변경해주는 함수.
setLike(parameter) ⇒ parameter로 state가 변경됨
state가 변경되면 리렌더링된다! → 화면에 변경된 값이 표시된다.
destructuring 문법? 왜 저렇게 써?
useState함수를 쓰면 다음과 같이 길이가 2인 배열이 만들어진다.
[상태값, 상태값을 변경해주는 함수]
각각에 변수명을 붙여주고 싶다면
const state = useState(0);
const like = state[0];
const setLike = state[1];
이렇게 일일이 지정해줘야하는데, destructuring문법을 쓰면 코드 한줄로 가능해
const [a, b] = ['안녕', '잘가']; //이렇게 한번에 변수에 선언, 할당가능
console.log(a); // '안녕'
최상위(at the top level)에서만 Hook을 호출해야 합니다. 반복문, 조건문, 중첩된 함수 내에서 Hook을 실행하지 마세요.
React 함수 컴포넌트 내에서만 Hook을 호출해야 합니다. 일반 JavaScript 함수에서는 Hook을 호출해서는 안 됩니다. (Hook을 호출할 수 있는 곳이 딱 한 군데 더 있는데, 바로 직접 작성한 custom Hook 안. )
useState실습 : 한 줄 소개 입력 + 열었다 닫았다 하기
저번에 배운 이벤트핸들링과 함께~
import React, { useState } from "react";
//CreateBio라는 함수형 컴포넌트
function CreateBio() {
const [open, setOpen] = useState(false);//초기값 : false:닫혀있는 걸로 설정하기위해
const [text, setText] = useState("");//초기값 : 빈 문자열
const [bio, setBio] = useState("아직 자기소개가 없습니다.");//초기값
//open값을 변경해주는 함수를 실행시키는 이벤트 핸들러만들기
const onToggle = () => {
setOpen(!open); // open값을 바꿔줌(false면 true로, true면 false로)
}
const onChange = (e) => {
setText(e.target.value); //input창의 value = 입력값으로 text를 바꿔줌
}
const onSubmit = () => {
setBio(text); //text를 bio로 설정해줌.
setText("") //설정해주고 input창은 빈칸으로
}
return (
<>
{***open &&*** ( //open이 true면 {}안에있는 태그들이 return되고, false면 X
<input onChange={onChange} value={text}/> //input에 입력되는 값을 text라는 state.
<button onClick={onSubmit}>리스트에 올리기</button>
)}
<button onClick={onToggle}>입력창 열기</button> //onClick에 onToggle함수 실행하도록
<h2>{text}</h2>
</>
)
}
export default CreateBio;
input의 value에 text라는 state를 지정해줬으므로 input에 입력할 때마다 value인 text가 변경되므로 리렌더링 될 것임
코드는여기에..
midsummernights/react-study-prac/createbio-hook-prac at main · mogamogua/midsummernights
우선 클래스형 컴포넌트, 함수형 컴포넌트를 다시 비교해보자면.
state를 가지고 있어 상태 변화에 대한 관리를 할 수 있음
단계별로 lifeCycle api를 사용할 수 있다.
life cycle?
리액트에서 화면은 언제 변화가 생기는가? →
- component가 mount되었을 때 (componentDidMount) - 처음 화면에 보여질때
- state가 변경되었을 때. (componentDidUpdate)
- component가 unmount될 때 (componentWillUnmount) - 화면에서 사라질때
선언하기가 비교적 간편
메모리 자원을 덜 사용
state, lifecycle API사용 불가능 ⇒ hook을 도입하면서 가능해짐
this
를 바인딩해주어야 했는데 이는 실수를 유발하고 코드가 장황해지기 쉬웠다. (사실 arrow function 사용하면 바인딩안해줘도됨)특정 컴포넌트 마운트 / 언마운트 되었을 때 함수 실행되게 할 수 있음
사라질때, 값이 바뀌기전에도 함수 실행되게 할 수있음 (이건 useEffect 내에 있는 클린업 함수에서)
왜 lifecycle api가 필요하냐? → 값(상태)가 변할 때, 화면에 뭔가 변화가 생겼을 때 어떤 동작을 수행하게 하고 싶을 때가 있을 것이다.
ex) 자기소개가 업로드 되었을 때, 프로필 완성 축하 메시지를 띄워주기
useEffect(callback, dependency array)
컴포넌트가 화면에 맨 처음 렌더링 될 때만 설정한 함수를 실행하고, 업데이트 시엔 실행되지 않게 하려면 : 함수 두번째 파라미터로 비어있는 배열 []를 넣어주면된다!
함수 두 번째 파라미터로 들어가는 배열에 검사하고 싶은 값을 넣어주면 된다.
예를 들어 name값이 변경되었을 때 함수가 실행되길 원하면
useEffect(() => {
console.log(name);
}, [name]);
이렇게.
배열 안에는 useState를 통해 관리하고 있는 상태를 넣어주어도 되고, props로 전달받은 값을 넣어주어도된다.
구조
useEffect(() => {
console.log("componentDidMount 화면에 처음 나타날 때 실행되는 함수야")
**return () => {
console.log("componentWillUnmount 컴포넌트가 사라질 때 실행되는 함수야")
}**
}, [])
useEffect(func, [특정값])
여기 정리가 아주 잘 되어 있어요. useEffect 더 잘 이해하고 싶다면 ㄱ ㄱ
import React, { useState, useEffect } from "react";
import style from "./bio.css";
//createTodo라는 함수형 컴포넌트
function CreateBio() {
const [open, setOpen] = useState(false);//초기값 : false:닫혀있는 걸로 설정하기위해
const [text, setText] = useState("");//초기값 : 빈 문자열
const [bio, setBio] = useState("아직 자기소개가 없습니다.");//초기값
**const [alert, setAlert] = useState("입력창을 열어보세요");**
//open값을 변경해주는 함수를 실행시키는 이벤트 핸들러만들기
const onToggle = () => {
setOpen(!open); // open값을 바꿔줌(false면 true로, true면 false로)
}
const onChange = (e) => {
setText(e.target.value); //input창의 value = 입력값으로 text를 바꿔줌
}
const onSubmit = () => {
setBio(text); //text를 bio로 설정해줌.
setText("") //설정해주고 input창은 빈칸으로
}
function InputWrapper () {
**useEffect (() => {
setAlert("입력창이 열렸어요");
return () => {
setAlert("입력창이 닫혔어요");
}
}, []);**
return (
<div className="inputWrapper">
<input onChange={onChange} value={text} />
<button onClick={onSubmit}> 리스트에 올리기</button>
</div>
)
};
return (
<div id="createBio">
{open && //open이 true면 {}안에있는 태그들이 return되고, false면 X
**<InputWrapper onChange={onChange} onSubmit={onSubmit} text={text} setAlert={setAlert}/>
}**
<button class="toggleBtn" onClick={onToggle}>입력창 열기</button> <span>{alert}</span>
<h2>{bio}</h2>
</div>
)
};
export default CreateBio;
열고 닫을 때 알림 뜬다!! 닫을 때(닫기직전): clean up함수 실행됨. 열 때: mount되면서 callback함수 실행됨 의존배열은 빈배열로 넣어야해!! 그래야 unmount되기 직전 clean up함수실행됨 :sparkle: useEffect 예제코드 · mogamogua/midsummernights@c048649**const inputRef = useRef(null);
//useRef() 를 사용하여 Ref 객체를 만들기**
const onInsert = useCallback(() => {
...
**inputRef.current.focus();**
}, [])
return (
<input **ref={inputRef}** />
)
const nextId = useRef(4);
nextId.current += 1 // 값 바뀌어도 리렌더링 되지않음~
useRef()
를 사용 할 때 파라미터를 넣어주면, 이 값이 .current
값의 기본값이 된다.
그리고 이 값을 수정 할때에는 .current
값을 수정하면 되고 조회 할 때에는 .current
를 조회하면 된당.
import React, { useState, useRef } from "react"; //createTodo라는 함수형 컴포넌트**const textInput = useRef(); // useRef함수 사용해서 Ref객체를 만들어준다.
// 이후, 선택하고 싶은 DOM에 속성으로 ref값을 넣어준다.**
... const onSubmit = () => {:sparkle: useRef사용하여 focus 설정하기 · mogamogua/midsummernights@aca2a6a
시간관계상 useRef로 dom api다루는 것만 하지만 다른 용도로도 사용하는 코드 작성해보면좋을듯!
수정
삭제된 댓글입니다.