useState
상단 form에서 Text를 입력했을 때 아래 리스트의 텍스트에 값이 나오도록 해준다.
먼저 상태를 등록해야하고, 이벤트 리스너를 통해 리액트로 알려줘야한다.
이벤트 리스너
리액트에서 이벤트 리스너를 달아주기 위해서는 함수를 만들고 onChange 등 속성에 함수를 달아주면 된다.
그리고 eneteredbody에 이벤트 값을 저장하였다가 <p>{eneteredBody}</p> 를 통해 값이 나오게 해본다.
import classes from './NewPost.module.css';
function NewPost() {
let enteredBody = '';
function changeBodyHandler(event) {
console.log(event.target.value);
enteredBody = event.target.value;
}
return (
<form className={classes.form}>
<p>
<label htmlFor="body">Text</label>
<textarea id="body" required rows={3} onChange={changeBodyHandler}/>
</p>
<p>{enteredBody}</p>
<p>
<label htmlFor="name">Your name</label>
<input type="text" id="name" required />
</p>
</form>
);
}
export default NewPost;
// jsx에서는 <label>에서 for대신 htmlFor를 사용한다.
// onChange={}에 사용할 함수를 넣어준다. 함수를 실행시키는 것이 아니라 ()는 제외한다.
// 함수도 객체라서 속성 값으로 함수를 지정할 수 있다. -> 리액트는 해당 함수를 이벤트 리스너 함수로 알고 이벤트가 일어날 때 자동으로 실행한다.
하지만 이렇게 해도 텍스트는 나타나지 않는다. jsx는 컴포넌트 코드를 한번만 가져오기 떄문이다. 리액트는 변경사항을 알수가 없다.
useState
리액트에는 use~로 시작되는 빌트인 함수가 있다. 이것들을 리액트 훅이라고 부른다.
이러한 함수들은 컴포넌트 함수 안에서만 사용해야한다. 컴포넌트 관련 무언가를 변경해줄 때 사용한다.
useState는 어떤 값을 넣어 해당 컴포넌트의 상태값으로 저장한다.
()안에는 기본값을 넣어두는데 어떤 타입도 가능하다.
useState는 2개의 항목을 가지는 배열을 반환하는데 첫번째 항목은 상태의 현재값이고 두번째 항목은 상태를 업데이트하는 함수이다.
상태를 업데이트 하는 함수를 이용해서 상태값을 변경시킬 수 있다.
함수를 통해 상태값을 업데이트하면 리액트는 메모리에 올려놓은 상태값을 변경시켜주면서 상태값이 저장되어 있는 컴포넌트 함수를 다시 호출해줘서 UI가 변경된다. 이때 DOM을 모두 업데이트하는 것이 아니라 리액트가 비교해서 해당 부분만 업데이트한다.
import { useState } from 'react';
import classes from './NewPost.module.css';
// 리액트 훅 : use~ 로 시작되는 리액트 빌트인 함수이다. 컴포넌트의 무언가를 리액트에 알려줄 때 사용한다.
function NewPost() {
// 배열 구조 분해 할당을 사용해서 useState()의 배열값을 사용한다.
const [ enteredBody, setEnteredBody ] = useState(''); // 업데이트 되면 항상 상수가 되기에 const로 설정
function changeBodyHandler(event) {
setEnteredBody(event.target.value); // update
}
return (
<form className={classes.form}>
<p>
<label htmlFor="body">Text</label>
<textarea id="body" required rows={3} onChange={changeBodyHandler}/>
</p>
<p>{enteredBody}</p>
<p>
<label htmlFor="name">Your name</label>
<input type="text" id="name" required />
</p>
</form>
);
}
export default NewPost;
하지만 원하는 것은 아래 리스트 카드의 텍스트가 변경되는 것이다.
현재 입력창과 카드리스트의 컴포넌트가 서로 다르다.
입력창은 NewPost이고 카드리스트는 PostsList이다. PostsList안에 NewPost가 위치하고 있다.
import NewPost from "./NewPost";
import Post from "./Post";
import classes from './PostsList.module.css'
function PostsList() {
// 형제 요소를 같이 둘 수 없어서 빈 요소를 넣어준다 : 상위요소 하나를 만들어주는것 <>
return (
<>
<NewPost/>
<ul className={classes.posts}>
<Post author = "soi" body= "react awsome!"/>
<Post author = "ruby" body = "hello react"/>
</ul>
</>
);
}
export default PostsList;
즉 A 컴포넌트의 값을 B 컴포넌트에서 상태관리를 해줘야 하는 것이다. props를 사용하면 된다.
import { useState } from "react";
import NewPost from "./NewPost";
import Post from "./Post";
import classes from './PostsList.module.css'
function PostsList() {
const [enteredBody, setEnteredBody] = useState('');
const [enteredAuthor, setEnteredAuthor] = useState('');
// 해당 enteredBody는 NewPost.jsx에 있다. 변경되는 값을 사용하는 곳은 PostsList.jsx임.
// A 컴포넌트에서 관리하는 상태값을 B 컴포넌트에서 사용해야함 -> 상태 올리기
// B 컴포넌트에서 상태값을 업데이트하는 함수를 만들고 A 컴포넌트의 props로 해당 함수를 넘겨준다.
// A 컴포넌트에서 props로 전달받은 함수를 사용해 관리해야하는 값을 넘겨주고 B 컴포넌트에서 상태를 관리한다.
// B 컴포넌트의 상태관리 함수를 A 컴포넌트와 연결해주는 것
function bodyChangeHandler(event) {
setEnteredBody(event.target.value);
}
function authorChangeHandler(event) {
setEnteredAuthor(event.target.value);
}
// 형제 요소를 같이 둘 수 없어서 빈 요소를 넣어준다 : 상위요소 하나를 만들어주는것 <>
return (
<>
<NewPost onBodyChange={bodyChangeHandler} onAuthorChange={authorChangeHandler}/>
<ul className={classes.posts}>
<Post author = {enteredAuthor} body= {enteredBody}/>
<Post author = "ruby" body = "hello react"/>
</ul>
</>
);
}
export default PostsList;
import classes from './NewPost.module.css';
function NewPost(props) {
// 상태관리할 텍스트 넘기기
// props.onBodyChange를 통해 PostsList.jsx에 텍스트를 넘겨준다.
return (
<form className={classes.form}>
<p>
<label htmlFor="body">Text</label>
<textarea id="body" required rows={3} onChange={props.onBodyChange}/>
</p>
<p>
<label htmlFor="name">Your name</label>
<input type="text" id="name" required onChange={props.onAuthorChange}/>
</p>
</form>
);
}
export default NewPost;
PostsList에 useState()를 사용하고 상태관리 함수를 NewPost의 props로 넘겨준다.
-> NewPost에서는 props로 받은 함수를 텍스트 입력 이벤트에 넣어줌으로써 PostsList의 상태관리 함수와 연결되어진다.