Hooks 는 React 16.8 에서 추가 되었습니다.
기존에는 함수형 컴포넌트에서 상태를 관리하기 위해서는 클래스 컴포넌트 다시 작성해야 했던 반면에, Hooks가 나오면서 함수형 컴포넌트에서도 상태를 가질 수 있게 되었습니다. Hooks는 이것 외에도 다양한 기능들을 제공합니다.
함수형 컴포넌트에서 상태를 가질 수 있게 해주다보니 클래스형 컴포넌트보다 함수형 컴포넌트를 더 많이 사용하고 있습니다.
그러나 Hooks를 도입한다고 해서 이전에 배웠던 리액트에 대한 개념들이 필요 없어지거나 하지는 않습니다. Hooks는 우리가 이미 알고 있던 props, state, context, refs, lifecycle 등에 대해서 더 직접적인 API를 제공해줄 뿐입니다.
즉, Hooks 는 class 를 이용하지 않고 state 와 다른 React 기능들을 사용할수 있게 합니다.
다음 아래 공식 문서를 참조하기바랍니다.
https://reactjs.org/docs/hooks-intro.html
다음으로 Hooks Api들을 살펴보겠습니다.
useState는 함수형 컴포넌트에서 state를 가질 수 있게 하는 Hook입니다.
const [state, setState] = useState(initialState);
useState는 두 개의 요소가 담긴 배열을 반환합니다. 첫 번째 요소는 컴포넌트의 현재 상태이고 두 번째 요소는 상태를 설정할 수 있는 함수입니다.
그리고 useState의 인자는 상태의 초기값을 나타냅니다.
초기값을 설정해주는거기 때문에 처음 랜더링을하고나서 이후에는 인자를 무시합니다.
function App() { // useState를 사용하여 count라는 state를 생성 초기값은 0으로 const [count, setCount] = useState(0); const add = () => {setCount(count+1);}//setCount로 state값 변경 const min = () => {setCount(count-1);} return ( <div> <p>Current COUNT : {count}</p> <button onClick={add}>+</button> <button onClick={min}>-</button> </div> ); }
useEffect 는 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정 할 수 있는 Hook 입니다. 클래스형 컴포넌트의 componentDidMount 와 componentDidUpdate 를 합친 형태로 보아도 무방합니다.
useEffect 를 적용해보겠습니다.
function App() { const [count, setCount] = useState(0); const add = () => {setCount(count+1);} const min = () => {setCount(count-1);} useEffect(() => { console.log('마운트 될 때만 실행됩니다.'); }); return ( <div> <p>Current COUNT : {count}</p> <button onClick={add}>+</button> <button onClick={min}>-</button> </div> ); } export default App;
버튼을 클릭하여 state를 변경했을때 다시 랜더링이되면서 useEffect가 타는걸 볼 수 있습니다.
useEffect를 마운트 될 때만 실행하고 싶을 경우에는 두번째 파라미터에 비어있는 배열을 넣어주면 처음에만 발생하고 그 이후 랜더링이 될 때에는 발생하지 않는걸 확인할 수 있습니다.
useEffect(() => {
console.log('랜더링~');
},[]);
그리고 특정 값이 없데이트 될 때만 실행 하고 싶을 때는 두번째 파라미터에 [특정값]을 넣어주면 됩니다.
useRef 를 사용하여 ref 를 설정하면, useRef 를 통해 만든 객체 안의 current 값이 실제 엘리먼트를 가르키게 됩니다
이벤트를 발생했을 때 e.target.value로 해당 값을 가져오는 방법을 useRef를 사용하여 값을 가져 올 수 있습니다.
function App() { const textRef = useRef(); const changeE = (e)=>{ let eValue = e.target.value; let refValue = textRef.current.value; console.log(eValue,refValue); } return ( <div> <input type = "text" ref= {textRef} onChange = {changeE}></input> </div> ); } export default App;
textbox에 입력을 했을때 개발자도구 console창에 동일하게 값이 나오는 걸 볼 수 있습니다.
이 3가지의 hooksApi를 사용하여 text를 입력받아 추가를 하면 목록에 추가되면서 카운팅이 되고, 목록에 추가된 데이터를 클릭 시 카운팅이 감소되는 예제를 만들어보겠습니다.파일은 총 App, Header, List, Item, Item.css 총 5개 파일을 사용할 것입니다.
Item.css
Item.css파일을 만듭니다.
용도는 화면에 할일을 추가한 목록 js공부, react을 클릭 시 변화를 주기 위함입니다.
.done {
text-decoration: line-through;
font-style: italic;
}
App.js
import List from './List.jsx'; import React, { Component, useState, useEffect } from 'react'; import Header from './Header.jsx'; import Form from './Form.jsx'; export const TodoContext = React.createContext();
const App = () => { //useState를 사용하여 state 생성, 초기값 지정 const [state, setState] = useState([ {"id" :"js공부", "status" : "re"}, {"id" :"react", "status" : "re"}]); const[newTodo, setNewTodo] = useState();//useState를 사용하여 newTodo 생성 초기값 없음 const changeInputData = (e) =>{ // onChange 이벤트 발생 시 NewTodo에 해당 값 저장 setNewTodo(e.target.value); } const addTodo = (e) => { // onClick 이벤트 발생 시 state에 해당 값 저장 e.preventDefault(); setState([...state, {id : newTodo, status : 're'}]); } const changeT = (id) => { // 할 일 목록 내 item을 클릭 시 발생하는 이벤트 클릭 시 해당 값에 변화를 주기 위함 const updateT = state.map(todo =>{ if(todo.id === id){ if(todo.status === 'done') todo.status= 're'; else todo.status = 'done'; } else{ } return todo; }); setState(updateT); } useEffect( () =>{ //랜더링 될 때 호출 console.log('새로운 내용이 랜더링됐네요', state); }, [state]); // 특정값 state에 지정하였기 때문에 newTodo가 변경될때는 타지 않음 return ( <> <Header state = {state}></Header> <form action=""> <input type="text" name="" onChange={changeInputData} /> <button onClick={addTodo}>할일추가</button> </form> <List todos= {state} changeT = {changeT}></List> </> ) } export default App;
Header.jsx
여기에서는 할 일 목록 갯수를 보여줍니다.
filter() 함수를 사용하여 인자값으로 넘어온 stat의 status값이 "re"인 것만 카운팅 하여 보여줍니다.
import React, { useMemo } from "react"; import { TodoContext } from "./App.js"; const Header = ({ state }) => { const count = (state) => { let cnt = state.filter((v) => v.status === "re").length; return cnt; }; return ( <div> <h1>Hooks를 사용한 예제</h1> <div>갯 수 : {count(state)}개</div> </div> ); }; export default Header;
List.jsx
여기에서는 할 일 목록을 보여줍니다.
map() 함수를 사용하여 상위 컴포넌트에서 전달받은 인자값을 item에게 넘겨줍니다.
import Item from "./Item.jsx"; import React, { useContext } from "react"; import { TodoContext } from "./App.js"; const List = ({ todos, changeT }) => { let todoList = todos.map((todo) => ( <Item todo={todo} changeT={changeT}></Item> )); return ( <div> <ul>할 일 목록{todoList}</ul> </div> ); }; export default List;
item.jsx
여기에서는 인자값으로 받은 todo에 status값을 확인하여 css를 변화를 줄 수 있게 해줍니다.
import "./item.css"; const Item = ({ todo, changeT }) => { const toggleItem = (e) => { const id = e.target.dataset.id; changeT(id); }; let classNm = ""; // status가 "done"인 경우 css를 입힐 수 있게 값을 저장합니다. if (todo.status === "done") { classNm = "done"; } else { classNm = ""; } return ( <div> <li data-id={todo.id} className={classNm} onClick={toggleItem}> {todo.id} </li> </div> ); }; export default Item;
이렇게 코드를 작성한 후 실행하여
hooks를 입력하고 할일추가버튼을 클릭하면
할 일 목록에 hooks가 추가가되고, 갯수가 증가하는 걸 확인 할 수 있습니다.
또 hooks를 클릭하였을 경우
hooks에 줄이 쳐지는 css가 정상 적용되며 갯 수가 줄어드는 걸 확인할 수 있습니다.
3가지 hooksAPI를 사용하여 예제를 만들어보았습니다.
다음에는 나머지 API를 보도록 하겠습니다.