한가지 참고해야 할 점은, state system에서는 두가지를 한꺼번에 업데이트할때 state = { activeIndex: 0,term:'' } 이렇게 한줄로 할 수 있지만, hook system에서는 const [activeIndex, setActiveIndex] = useState(0); const [term, setTerm] = useState(''); 이렇게 새로 적어야한다.
useState : functional component안에서 state를 사용할 수 있는 접근권한을 준다.
useEffect : class component의 lifecycle method와 같은 역할을 한다.
useRef : ref를 만들수 있게 해준다.
(위의 세가지는 모두 function들이다.)
버튼을 클릭할때마다 숫자가 1씩 카운트 되게 하기
const {useState} = React;
export default function App() {
const [count, setCount] = useState(0);
const onButtonClick = () => {
setCount(count + 1);
}
return (
<div>
<button onClick={onButtonClick}>Click me</button>
<h1>Current count :{count} </h1>
</div>
)
}
이 코드는 아래와 같이 바꿀 수도 있다. 둘다 같은 기능
export default function App() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => {setCount(count+1);
}}>Click Me!</button>
<h1>Current Count:{count}</h1>
</div>
);
}
여기에서 [count, setCount] 는
array 안에 있는 element들을 쉽게 가져올 수 있는 short cut이라고 생각하면 된다.
count는 우리가 계속 tracking하는 state로, 계속해서 값이 변한다.
setCount는 function으로 우리가 state를 update하기 위해 부른다.
null 은 이 state를 위한 initial value이다. (가장 처음에만 null이고 업데이트를 하게되는 두번째부터는 더이상 null이 아닌 업데이트한 값으로 바뀐다.)
useState with object
import React, { useState } from 'react';
const UseStateObject = () => {
const [person, setPerson] = useState({
name: 'peter',
age: 24,
message: 'random message'
});
const changeMessage = () => {
setPerson({...person, message: 'hello world'}) // 모든 person을 불러온다음, 그중에서 message키의 value만 바꿔준다.
};
return (
<>
<h3>{person.name}<h3>
<h3>{person.age}<h3>
<h3>{person.message}<h3>
<button onclick={changeMessage}>
change message
</button>
</>
);
};
import React, { useState, useEffect } from 'react';
const Search = () => {
const [term, setTerm] = useState('');
useEffect(() => {
console.log('heyheyhey');
}, );
//여기에서 두번째 argument로 들어가는 것이 '언제' 코드가 실행되는지를 컨트롤 한다.
return (
)
}
- 두번째 인자에 들어갈 수 있는 것은 3가지가 있다.
- []: 우리가 쓴 arrow function을 (첫번째 인자를) component가 맨 처음 render될때만 실행
- 아무것도 안들어가는 것: 맨 처음 render될때 + 그 후로 매번 re-render될때 실행
- [term] : 맨 처음 render 될때 + array안에 있는 data값이 변경될 때만 실행
1번: 임시 변수 선언 <- react에서 가장 추천하는 방식
useEffect(() => {
const search = async () => {
await axios.get('https://api.github.com/users');
};
search();
}, [term]);
또 다른 방식
import React, { useState, useEffect } from 'react';
const UseEffectApi = () => {
const [user, setUsers] = useState([]);
const getUsers = async() => {
const response = await getch('https://api.github.com/users');
const users = await response.json();
setUsers(users);
};
useEffect(()=> {
getUsers();
},[])
return (
{users.map((user)=> {
}}
)
};
2번: 1번에서 const를 지우고 ()를 더하기 (1번과 기능은 완전히 같음, 좀 더 코드가 심플할 뿐)
useEffect(() => {
(async () => {
await axios.get('https://api.github.com/users');
})();
}, [term]);
3번: promise 이용
useEffect(() => {
axios.get('https://api.github.com/users')
.then((response) => {
console.log(response.data);
});
}, [term]);
import React, { useRef } from 'react';
const UseRef = () => {
const refContainer = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
console.log(refContainer.current.value);
};
return (
<>
<form onSubmit={handleSubmit}
<input type="text" ref={refContainer}/>
<button type="submit">submit</button>
</form>
</>
)
}
이제 input창에 글자를 치고 submit버튼을 누를때마다 value값이 refContainer에 저장된다.
기본문법
const [state, dispatch] = useReducer(reducer, );
첫번째 argument reducer은 action을 dispatch할때 실행되는 코드(state를 manipulate한다)
두번째 argument defaultState는 initial state로, 따로 변수로 선언하지 않고 ()안에서 object형태로 선언해도 된다.
import React, { useState, useReducer } from 'react';
const reducer = (state, action) => {
if (action.type === 'ADD_ITEM') {
const newPeople = [...state.people, action.payload];
return {
...state,
people: newPeople,
isModalOpen: true,
modalContent: 'item added',
};
}
if (action.type === 'NO_VALUE') {
return { ...state, isModalOpen: true, modalContent: 'please enter value' };
}
if (action.type === 'CLOSE_MODAL') {
return { ...state, isModalOpen: false };
}
if (action.type === 'REMOVE_ITEM') {
const newPeople = state.people.filter(
(person) => person.id !== action.payload
);
return { ...state, people: newPeople };
}
throw new Error('no matching action type');
};
const defaultState = {
people: [],
isModalOpen: false,
modalContent: '',
};
const Index = () => {
const [name, setName] = useState('');
const [state, dispatch] = useReducer(reducer, defaultState);
const handleSubmit = (e) => {
e.preventDefault();
if (name) {
const newItem = { id: new Date().getTime().toString(), name };
dispatch({ type: 'ADD_ITEM', payload: newItem });
setName('');
} else {
dispatch({ type: 'NO_VALUE' });
}
};
const closeModal = () => {
dispatch({ type: 'CLOSE_MODAL' });
};
return (
<>
{state.isModalOpen && (
<Modal closeModal={closeModal} modalContent={state.modalContent} />
)}
<form onSubmit={handleSubmit} className='form'>
<div>
<input
type='text'
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
<button type='submit'>add </button>
</form>
{state.people.map((person) => {
return (
<div key={person.id} className='item'>
<h4>{person.name}</h4>
<button
onClick={() =>
dispatch({ type: 'REMOVE_ITEM', payload: person.id })
}
>
remove
</button>
</div>
)})};
</>
)};
export default Index;