자식컴포넌트에 dispatch 넘겨서 사용
import React, { createContext, useReducer, useState } from 'react';
import Button from './components/Button';
export const UserContext = createContext(null);
function App(props) {
const reducer = (current_state, action) => {
switch (action.type) {
case "ADD":
return [...current_state, action.xxx];
case "DEL":
return [current_state.filter((v, i)=>v!= action.xxx)]
default:
return current_state;
}
}
const [item, setItem] = useState();
const [items, dispatch] = useReducer(reducer, []);
function handleChange(event){
setItem(event.target.value);
}
console.log(items);
return (
<>
<UserContext.Provider value={[dispatch, item]}>
<div>
<input type='text' value={item} onChange={handleChange}></input>
<Button></Button>
</div>
{items}
</UserContext.Provider>
</>
);
}
export default App;
import React, { useContext } from 'react';
import { UserContext } from '../App';
function Button(props) {
const [dispatch, item] = useContext(UserContext);
return (
<div>
<button onClick={()=>dispatch({type:"ADD", xxx:item})}>+</button>
<button onClick={()=>dispatch({type:"DEL", xxx:item})}>-</button>
</div>
);
}
export default Button;


라이프사이클 훅 메서드들은 클래스형 컴포넌트에서만 사용할 수 있다.
이를 대체한게 useEffect다.
콜백함수가 몇번 실행될지가 배열과 연관이 있다.
반환값이 없다.
익명함수는 바로 실행되지 않고 App이 실행되어 DOM이 랜더링된 후에 비동기로 실행된다. 이후[의존성배열]에 의해서 익명함수의 재실행 여부가 결정된다.
익명함수는 바로 실행되지 않고 App이 실행되어 DOM이 랜더링된 후에 비동기로 실행된다.
만약 [의존성배열]을 지정하면 값일 변경될 때만 익명함수가 재실행되고
지정하지 않으면 App이 다시 실행될 때마다 익명함수도 재실행된다.
만약 [] 빈 배열을 지정하면 종속값이 없기 때문에 익명함수는 단 한번만 실행된다.
strict 모드로 실행하면 2번 호출. index.js 수정.
[] 빈배열을 자주 쓸 거임.
화면 로딩시 서버에서 데이터 가져오는 용도로 많이 사용할 것임
약간 jquery의 ajax, Vue의 axios와 비슷한 역할을 수행한다.
요약: 변수, 랜더링, 최초 기준으로 정해진 함수를 실행 (DOM이 랜더링 된 후에 실행되어야하므로 App이 먼저 실행된 후에 비동기로 실행된다.)
예제
import React, { useEffect, useState } from 'react';
function App(props) {
const [number, setNumber] = useState(0);
useEffect(()=>{
console.log("useEffect number값이 변경됨");
}, []);
console.log("App 호출");
return (
<div>
<h1>{number}</h1>
<button onClick={()=>setNumber(()=>number+1)}>+</button>
<button onClick={()=>setNumber(()=>(number<1)?number:number-1)}>-</button>
</div>
);
}
export default App;
인라인 이벤트 onClick등을 제거하고 useEffect로 구현해보기
예제
import React, { useEffect, useState } from 'react';
function App(props) {
const [num, setNum] = useState(0);
useEffect(()=>{
//document.getElementById("plus").addEventListener('click', plus);
document.querySelector("#plus").addEventListener('click', plus);
console.log("useEffect");
},[]);
function plus(){
setNum(()=>num+1);
console.log("plus");
}
console.log("app", num);
return (
<div>
<h1>{num}</h1>
<button id="plus">+</button>
</div>
);
}
export default App;

부모가 자식에게 전달하는 props가 똑같을 때, 부모가 랜더링되고 자식은 랜더링이 필요가 없어진다. 이때 memo를 통해 자식의 랜더링을 방지할 수 있다.
사용법 : 자식 컴포넌트를 메모로 묶어주면 된다.
import React, { useState } from 'react';
import Counter from './components/Counter';
import Counter2 from './components/Counter2';
import Counter3 from './components/Counter3';
import Counter4 from './components/Counter4';
function App(props) {
const [num, setNum] = useState(0);
function handleEvent(){
setNum(num+1);
}
console.log("App");
return (
<div>
<Counter></Counter>
<Counter2 initialCount={num}></Counter2>
<Counter3 initialCount={10}></Counter3>
<Counter4 initialCount={10}></Counter4>
<button onClick={handleEvent}>click</button>
<hr></hr>
{num}
</div>
);
}
export default App;
import React from 'react';
import {memo} from 'react';
const Counter4 = memo(
({initialCount = 0}) =>{
console.log("count4");
return (
<div>
count4값 : {initialCount}
<br/>
</div>
);
}
)
export default Counter4;
useEffect와 비슷한 기능을 하며, 차이점은 동일한 입력이 들어오면 이전에 저장해둔 복잡한 연산의 결과값을 추가 연산 없이 사용하여 성능을 최적화시킬 수 있다는 점이다.
콜백함수와 배열을 인자로 가지며, 성능을 최적화시킬 수 있는 대표적인 hook 중 하나다.
여기서 입력이란 을 뜻하며, 배열의 요소값이 업데이트될 때만 콜백함수를 다시 호출한다.
만약 빈 배열을 지정하면 맨 처음 컴포넌트가 마운드되었을 때만 값을 계산하고 이후에는 항상 memoization된 값을 반환한다.
결과적으로 콜백함수가 리턴시킨 결과값을 반환한다.

https://velog.io/@jinyoung985/React-useMemo%EB%9E%80
이런 경우에 사용할 수 있다:
객체를 담은 변수를 useEffect의 배열에 담았다.
그리고 다른 useState로 변경한 state로 인해 App이 랜더링되었다.
그러면 객체의 주소값이 변경되고 useEffect가 실행되게된다.
...
...
unction App() {
const [number, setNumber] = useState(1);
const [isKorea, setIsKorea] = useState(true);
// 1번 location
const location = {
country: isKorea ? "한국" : "일본"
};
// 2번 location
// const location = useMemo(() => {
// return {
// country: isKorea ? '한국' : '일본'
// }
// }, [isKorea])
useEffect(() => {
console.log("useEffect 호출!");
}, [location]);
return (
<header className="App-header">
<h2>하루에 몇 끼 먹어요?</h2>
<input
type="number"
value={number}
onChange={(e) => setNumber(e.target.value)}
/>
<hr />
<h2>내가 있는 나라는?</h2>
<p>나라: {location.country}</p>
<button onClick={() => setIsKorea(!isKorea)}>Update</button>
</header>
);
}
export default App;
보충학습
https://velog.io/@goyou123/React-Hooks-%EC%B4%9D%EC%A0%95%EB%A6%AC
개인적 설치 : 크롬 json viewer 확장프로그램 사용
더미데이터 제공하는 서버 사이트 : https://reqres.in/
아래에 보면 여러가지 api요청주소와 반환받는 데이터를 보여준다.
이를 이용하여 프론트엔드에서 api 테스트를 수월히 진행할 수 있다.
// fetch로 비동기 통신
// fetch는 Promise 객체를 반환함
// fetch 비동기 요청 :promise 객체 리턴 => await 처리
// await 사용함수는 전체를 async처리 해주어야함
// await을 사용하기 위해서는 함수에 async를 추가해줘야함
export async function fetchUserList(){
const response = await fetch("https://reqres.in/api/users?page=2");
const resData = await response.json();
console.log(resData);
return resData.data;
}
import React, { useEffect, useState } from 'react';
import UserList from './components/UserList';
import { fetchUserList } from './http';
function App(props) {
const [usersList, setUsersList] = useState([]);
useEffect(()=>{
// await을 사용하기 위해서는 함수에 async를 추가해줘야함
async function xxx(){
//비동기 함수의 구현
const usersList = await fetchUserList();
setUsersList(usersList);
}
xxx();
}, [])
return (
<div>
<h1>User목록</h1>
<UserList users={usersList}></UserList>
</div>
);
}
export default App;
import React from 'react';
function UserList(props) {
const {users} = props;
return (
<div>
<table border={1}>
<thead>
<tr><th>아이디</th><th>이름</th><th>사진</th></tr>
</thead>
<tbody>
{users.map((user,idx)=>{
return (
<tr key={idx}>
<td>{user.id}</td>
<td>{user.first_name}</td>
<td><img src={user.avatar} width="50" height="50"/></td>
</tr>
)
})}
</tbody>
</table>
</div>
);
}
export default UserList;
이거 하기 전에 fetch와 promise 객체에 대해서 알아야 사실 정확한 이해가 가능할 것 같다.
자바스크립트 fetch 간편 정보 : https://www.doyeon0430.com/engineer/django/54/

const resData = await response.json();
return resData.data;
http.js
// fetch로 비동기 통신
// fetch는 Promise 객체를 반환함
// fetch 비동기 요청 :promise 객체 리턴 => await 처리
// await 사용함수는 전체를 async처리 해주어야함
export async function fetchUserList(){
const response = await fetch("https://reqres.in/api/users?page=2", {
method: "get"
});
console.log("response 객체 정체: ", response);
if(!response.ok){
console.log("fetchUserList.Error");
throw new Error("UserList 요청 예외")
}
const resData = await response.json();
console.log(resData);
return resData.data;
}
App.js
import React, { useEffect, useState } from 'react';
import UserList from './components/UserList';
import { fetchUserList } from './http';
import Error from './components/Error';
function App(props) {
const [usersList, setUsersList] = useState([]);
const [isFetching, setIsFetching] = useState(false);
const [error, setError] = useState();
useEffect(()=>{
async function xxx(){
setIsFetching(true); //fetching 가져오는 중
//비동기 함수의 구현
try {
const usersList = await fetchUserList()
setUsersList(usersList);
} catch (error) {
console.log("Error: ", error.message);
setError({message: error.message});
} finally {
setIsFetching(false);
}
}
xxx();
}, [])
return (
<div>
<h1>User목록</h1>
{error && (
<Error title="User목록 : 예외발생됨" message={error.message}></Error>
)}
{!error && (
<UserList
isLoading={isFetching}
users={usersList}
loadingText="Fetching your users...."
fallbackText="No users available"
></UserList>
)}
{/* <h1>User목록</h1>
{(isFetching)?
<p style={{color:"red"}}>fetching loading...</p>
:
(error)?<Error title="User목록 : 예외발생됨" message={error.message}></Error>:<UserList users={usersList}></UserList>
} */}
</div>
);
}
export default App;
userList.js
import React from 'react';
function UserList(props) {
console.log(props);
const {isLoading, users, loadingText, fallbackText} = props;
return (
<div>
{isLoading && <p style={{color: "red"}}></p>}
{!isLoading && users.length ==0 && (
<p style={{color:"blue"}}>{fallbackText}</p>
)}
{!isLoading && users.length>0&&(
<table border={1}>
<thead>
<tr><th>아이디</th><th>이름</th><th>사진</th></tr>
</thead>
<tbody>
{users.map((user,idx)=>{
return (
<tr key={idx}>
<td>{user.id}</td>
<td>{user.first_name}</td>
<td><img src={user.avatar} width="50" height="50"/></td>
</tr>
)
})}
</tbody>
</table>
)}
</div>
);
}
export default UserList;
Error.js
import React from 'react';
function Error(props) {
console.log("inError: ", props);
const {title, message} = props;
return (
<div>
<h2>{title}</h2>
<p>{message}</p>
</div>
);
}
export default Error;