useEffect , memo
2024. 3. 19. 21:54ㆍDaily Codig Reminder
button
import Button from "./components/Button";
import { createContext, useReducer,useState } from "react";
export const UserContext = createContext(null);
export default function App() {
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/>
</div>
{items}
</UserContext.Provider>
</>
);
}
import React from 'react';
import { useContext} from 'react';
import { UserContext } from '../App';
function Button() {
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 , memo
useEffect( 익명함수, [의존성배열])
useState, useRef와 다르게 반환값이 없다.
익명함수는 바로 실행되지 않고 App이 실행되어 DOM이 랜더링된 후에 비동기로 실 행된다.
이후 [의존성배열]에 의해서 익명함수의 재실행 여부가 결정된다.
만약 [의존성배열] 을 지정하면 값이 변경될 때만 익명함수가 재실행되고 지정하지 않으면
App이 다시 실행될 때마다 익명함수도 재실행된다.
만약 [] 빈 배열을 지정하면 종속값이 없기 때문에 익명함수는 단 한번만 실행된다.
의존성배열동작방식확인
import { useEffect, useState } from "react";
export default function App() {
//컴포넌트 함수 안에서 useState 선언
const [ number, setNumber] = useState(0);
//1. [의존성 배열] 에 state 값이 있는 경우 : number 값이 변경되면 부수효과함수가 재실행됨
//2. [] 빈배열을 지정한 경우 단 한번만 실행함
//3. 배열지정 안하면 APp이 재랜더링 될 때마다 부수효과함수가 재실행됨
//4. strict 모드로 실행하면 2번 호출, 1번 호출을 위해서는 index.js 수정
//DOM 이 생성된 후 useEffect 함수 실행함
useEffect (()=> {
console.log("useEffect number 값이 변경됨"); //부수효과함수
}, []) ; //배열 1번 실행
const onIncrease = () => {
setNumber (number +1);
};
const onDecrease = () => {
if (number >0 ){
setNumber (number>0 ? number-1: 0);
}
};
console.log("App 호출");
return (
<>
<h1>{number}</h1>
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
</>
);
}
useEffect 호출안되고 추가도 안됨
import { useEffect, useState } from "react";
export default function App() {
//컴포넌트 함수 안에서 useState 선언
const [ number, setNumber] = useState(0);
const [ number2, setNumber2] = useState(0);
//1. [의존성 배열] 에 state 값이 있는 경우 : number 값이 변경되면 부수효과함수가 재실행됨
//2. [] 빈배열을 지정한 경우 단 한번만 실행함
//3. 배열지정 안하면 APp이 재랜더링 될 때마다 부수효과함수가 재실행됨
//4. strict 모드로 실행하면 2번 호출, 1번 호출을 위해서는 index.js 수정
//DOM 이 생성된 후 useEffect 함수 실행함
useEffect (()=> {
console.log("useEffect number 값이 변경됨"); //부수효과함수
}, [number]) ; //배열 1번 실행
const onIncrease = () => {
setNumber (number +1);
};
const onIncrease2 = () => {
setNumber2 (number2 +1);
};
const onDecrease = () => {
if (number >0 ){
setNumber (number>0 ? number-1: 0);
}
};
console.log("App 호출");
return (
<>
<h1>{number}</h1>
<button onClick={onIncrease}>+</button>
<button onClick={onIncrease2}>number2+</button>
<button onClick={onDecrease}>-</button>
</>
);
}
DOM접근해서focus지정
import { useEffect, useRef } from "react";
export default function App() {
const inputRef= useRef();
//index.js 수정
//DOM 이 생성된 후 useEffect 함수 실행함 1번 실행
useEffect (()=> {
console.log("useEffect"); //부수효과함수
console.log(inputRef);
inputRef.current.focus();
}, []) ; //배열 1번 실행
console.log("App 호출");
return (
<>
<div>
아이디: <input type="text" ref={inputRef}/>
비번: <input type="text"/>
<button>저장</button>
</div>
</>
);
}
cleanup기능
import { useEffect, useState } from "react";
export default function App() {
const [number, setNumber] = useState(0);
//index.js 수정
//컴포넌트 함수 안에서 useState 선언
useEffect (()=> {
console.log("number 값이 변경됨");
//clean up 기능
return () => {
console.log("clean up ......");
};
}, [number]) // number 변경시 마다 useEffect 호출
const onIncrease = ()=> {
setNumber (number+1);
};
const onDecrease = () => {
if (number >0 ){
setNumber (number > 0 ? number - 1 : 0);
}
};
console.log("App 호출");
return (
<>
<h1>{number}</h1>
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
</>
);
}
cleanup기능2이벤트등록해제
number 써야 숫자가 더해짐
import { useEffect, useState } from "react";
export default function App() {
const [number, setNumber] = useState(0);
//index.js 수정
//컴포넌트 함수 안에서 useState 선언
useEffect (()=> {
console.log("effect");
document.querySelector("#up").addEventListener("click", handleEvent);
//최초 랜더링 시 설정되고 이후 재 랜더링 시 실행안됨
}, [number]) // number 변경시 마다 useEffect 호출
const handleEvent =(e) => {
setNumber(number+1);
}
console.log("App 호출");
return (
<>
<h1>{number}</h1>
<button id="up">+</button>
</>
);
}
성능이슈01memo함수함수컴포넌트_재사용기법
import { useState } from "react";
import Counter from './components/Counter';
import Counter2 from './components/Counter2';
import Counter3 from './components/Counter3';
import Counter4 from './components/Counter4';
export default function App() {
const [num, setNum] = useState(0);
const handleEvent =(e) => {
setNum(num+1);
}
console.log("App 호출");
return (
<>
{/* Counter 와 Counter2 는 부모인 App 가 재랜더링되면
자식도 항상 재랜더링됨*/}
<Counter/>
<Counter2 initialCount={num}></Counter2>
<Counter3 initialCount={10}></Counter3>
{/*부모인 App가 변경돼도
동일한 Props 를 전달하면 memo 된 자식이 재랜더링 안됨을 확인*/}
<Counter4 initialCount={40}></Counter4>
<button onClick={handleEvent}>click</button>
<hr/>
{num}
</>
);
}
import React from 'react';
export default function Counter({initialCount=0}) {
console.log("Counter ");
return (
<div>
count 값 : {initialCount}
<br/>
</div>
);
}
import React from 'react';
function Counter2({initialCount=0}) {
console.log("Counter2 ")
return (
<div>
counter2 값 :{initialCount}
</div>
);
}
export default Counter2;
import React from 'react';
export default function Counter3({initialCount=0}) {
console.log("Counter3 ");
return (
<div>
count3 값 : {initialCount}
<br/>
</div>
);
}
import React, { memo } from 'react';
//initialCount 는 항상 고정된 값이기 때문에 재랜더링 할 필요가 없음
const Counter4 = memo (({initialCount =0}) => {
console.log("Counter4");
return(
<>
count4 값 : {initialCount}
</>
)
})
export default Counter4;
indes.js 에서
</React.StrictMode> */ 막음
성능이슈02useMemo02함수재호출방지하여기존값재사용기법적용함
import { useState } from "react";
import { useMemo } from "react";
export default function App() {
const [count, setCount] = useState(0);
const increase = ()=>{
setCount(count+10);
}
//항상고정된 값을 리턴하는 경우
const calculateCompllexValue = useMemo (()=> {
console.log("calculateComplexValue");
return 2 * 2 * 987;
},[])
/*useMemo 적용 안된 예제
- increase 버튼을 클릭하면 count 값이 증가하고
재랜더링 되면서 complexValue 값을 다시 그리기 위해서
calculateComplexValue() 함수가 재실행된다
calculateComplexValue() 함수 안의 값이 항상 동일한 값임에도
불구하고 count 값이 변경괼 때마다 매번 호출된다. 성능이슈 발생 */
return (
<>
<button onClick={increase}>+</button>
count: {count}
<p>complexValue: {calculateCompllexValue}</p>
</>
);
}
error
import {useEffect, useState} from "react";
import {fetchUserList} from "./http.js"
import UsersList from './components/UsersList'
export default function App() {
const [usersList, setUsersList] = useState([]);
useEffect (()=>{
async function xxx(){
//비동기함수 구현
const usersList = await fetchUserList();
setUsersList(usersList);
}
xxx();
}, []);
console.log("App 호출")
return (
<>
<UsersList users={usersList} />
</>
);
}
export async function fetchUserList(){
//데이터 요청 응답 수신
const response = await fetch("https://reqres.in/api/users?page=2")
//fetch 비동기 요청 :promise 객체 리턴 => awit 처리
//await 사용 함수는 전체를 async 처리 해주어야함
const resData = await response.json();
console.log(resData);
return resData.data;
}
export default function UsersList({ users }) {
return (
<>
<table border="1">
<thead>
<tr>
<td>아이디</td>
<td>이름</td>
<td>사진</td>
</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"></img>
</td>
</tr>
);
})}
</tbody>
</table>
</>
);
}
import {useEffect, useState} from "react";
import {fetchUserList} from "./http.js"
import UsersList from './components/UsersList'
import Error from './components/Error';
export default function App() {
const [usersList, setUsersList] = useState([]);//사용자 목록
const [isFetching, setIsFetching] = useState(false); //로딩중 상태저장값
const [error, setError] =useState(); //에러
useEffect (()=>{
async function xxx(){ //가져오는 중
//비동기함수 구현
try{
const usersList = await fetchUserList();
setUsersList(usersList);
}catch(err){
console.log("catch Error: " , err.message);
setError({message: err.message});
}
setIsFetching(false); //가져오기 완료
const usersList = await fetchUserList();
setUsersList(usersList);
}
xxx();
}, []);
console.log("App 호출")
return (
<>
<h1>User 목록</h1>
{error && (
<Error title="User 목록 : 예외발생됨" message={error.message}></Error>
)}
{!error && (
<UsersList
isLoading = {isFetching}
users ={usersList}
loadingText="Fetching your users..."
fallbackText ="No Users available"
></UsersList>
)}
</>
);
}
import React from "react";
function UsersList({ users, isLoading, loadingText, fallbackText }) {
console.log("users:", users);
console.log("isLoading:", isLoading);
console.log("loadingText:", loadingText);
console.log("fallbackText:", fallbackText);
return (
<>
{isLoading && (
<p style={{ color: "red" }}>{loadingText}</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) => (
<tr key={idx}>
<td>{user.id}</td>
<td>{user.first_name}</td>
<td>
<img src={user.avatar} width="50" height="50" alt={`Avatar of ${user.first_name}`} />
</td>
</tr>
))}
</tbody>
</table>
)}
</>
);
}
export default UsersList;
export async function fetchUserList(){
//데이터 요청 응답 수신
const response = await fetch("https://reqres.in/api/users?page=2", {
//method:"GET" //정상요청
method:"PUT" //정상요청
//에러 실습은 PUT 으로 변경해서 테스트 할것
});
if (!response.ok){
console.log("FetchUserList.Error");
throw new Error ("UserList 요청 예외");
}
//fetch 비동기 요청 :promise 객체 리턴 => awit 처리
//await 사용 함수는 전체를 async 처리 해주어야함
const resData = await response.json();
console.log(resData);
return resData.data;
}
import React from 'react';
export default function Error({ title, message}) {
return (
<div>
<h2>{title}</h2>
<p>{message}</p>
</div>
);
}
error2
import {useEffect, useState} from "react";
import {fetchUserList} from "./http.js"
import UsersList from './components/UsersList'
import Error from './components/Error';
export default function App() {
const [usersList, setUsersList] = useState([]);//사용자 목록
const [isFetching, setIsFetching] = useState(false); //로딩중 상태저장값
const [error, setError] =useState(); //에러
useEffect (()=>{
async function xxx(){ //가져오는 중
//비동기함수 구현
setIsFetching(true);
try{
const usersList = await fetchUserList();
setUsersList(usersList);
}catch(err){
console.log("catch Error: " , err.message);
setError({message: err.message});
}
setIsFetching(false); //가져오기 완료
}
xxx();
}, []);
console.log("App 호출")
return (
<>
<h1>User 목록</h1>
{error && (
<Error title="User 목록 : 예외발생됨" message={error.message}></Error>
)}
{!error && (
<UsersList
isLoading = {isFetching}
users ={usersList}
loadingText="Fetching your users..."
fallbackText ="No Users available"
></UsersList>
)}
</>
);
}
export async function fetchUserList(){
//데이터 요청 응답 수신
const response = await fetch("https://reqres.in/api/users?page=2", {
//method:"GET" //정상요청
method:"PUT" //정상요청
//에러 실습은 PUT 으로 변경해서 테스트 할것
});
if (!response.ok){
console.log("FetchUserList.Error");
throw new Error ("UserList 요청 예외");
}
//fetch 비동기 요청 :promise 객체 리턴 => awit 처리
//await 사용 함수는 전체를 async 처리 해주어야함
const resData = await response.json();
console.log(resData);
return resData.data;
}
import React from 'react';
export default function Error({ title, message}) {
return (
<div>
<h2>{title}</h2>
<p>{message}</p>
</div>
);
}
import React from "react";
function UsersList({ users, isLoading, loadingText, fallbackText }) {
console.log("users:", users);
console.log("isLoading:", isLoading);
console.log("loadingText:", loadingText);
console.log("fallbackText:", fallbackText);
return (
<>
{isLoading && (
<p style={{ color: "red" }}>{loadingText}</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) => (
<tr key={idx}>
<td>{user.id}</td>
<td>{user.first_name}</td>
<td>
<img src={user.avatar} width="50" height="50" alt={`Avatar of ${user.first_name}`} />
</td>
</tr>
))}
</tbody>
</table>
)}
</>
);
}
export default UsersList;
'Daily Codig Reminder' 카테고리의 다른 글
Routing_loader (0) | 2024.03.24 |
---|---|
axios, router (0) | 2024.03.24 |
useRef (0) | 2024.03.19 |
useState 와 useRef (0) | 2024.03.19 |
useState, 이벤트, hook (0) | 2024.03.17 |