React

 

React Hooks 쉽게 마스터하기

 

별코딩

 

유튜브 강의 목록 :   https://www.youtube.com/playlist?list=PLZ5oZ2KmQEYjwhSxjB_74PoU6pmFzgVMO

 

1.useState 15분만에 마스터하기 

2.useEffect 깔끔하게 마스터하기 

3.useRef 완벽 정리 1# 변수 관리 

4.useRef 완벽 정리 2# DOM 요소 접근 

5.useContext + Context API 

6.useMemo 제대로 사용하기 

7. useCallback 짱 쉬운 강의 

8. useReducer 확실히 정리해드려요 

9.React.memo로 컴포넌트 최적화하기 (ft. useMemo, useCallback)

10.Custom Hooks 커스텀 훅 

 

 

* vscode  확장 패키지 추가

1. - Auto Import - ES6, TS, JSX, TSX

2. - Reactjs code snippets

3. - ESLint

4. - Prettier - Code formatter

Visual Studio Code 폴더/파일 아이콘 변경하기

 

* 리액트  프로젝트 생성

 npx create-react-app  경로

예) npx create-react-app E:\react-app2

 

 

* 넥스트 프로젝트 생성

$ npx create-next-app nextjs-tutorial

 

 

 

 

소스 : https://github.com/braverokmc79/react-hooks-drunk

 

 

 

 

 

1.useState 15분만에 마스터하기 

 

 

1) Stu1And1

import React, { useState } from 'react'

function Stu1And1() {

    const [time, setTime] = useState(1);

    const handleClick = () => {
        let newTime;
        if (time >= 12) {
            newTime = 1;
        } else {
            newTime = time + 1;
        }
        setTime(newTime);
    }

    return (
        <div>
            <span>현재 시각 : {time}시</span>
            <button onClick={handleClick}>Update</button>
        </div>
    )
}

export default Stu1And1

 

 

 

 

2) Stu1And2

 

import React, { useState } from 'react'

const heavyWork = () => {
  console.log("엄청 무거운 작업 초기값 콜백 설정시 맨 처음 랜더링 될때만 실행 !!!");
  return ['홍길동', '김민수'];
}

function Stu1And2() {

  const [Names, setNames] = useState(() => {
    return heavyWork();
  });

  const [Input, setInput] = useState('');

  const handleInputChange = (e) => {
    setInput(e.target.value);
  }


  const handleUpload = (e) => {
    setNames((prevState) => {
      console.log("이전 state : ", prevState);
      return [Input, ...prevState];
    })

    // setNames([...Names, Input]);
  }


  return (
    <div>
      <input type="text" value={Input} onChange={handleInputChange} />
      <button onClick={handleUpload}>Upload</button>

      <br />
      {
        Names.map((name, idx) => {
          return <p key={idx}>{name}</p>
        })


      }

    </div>
  )
}

export default Stu1And2

 

 

 

 

 

 

2.useEffect 깔끔하게 마스터하기

 

Stu2And1

import { useEffect, useState } from "react"


function Stu2And1() {

  const [Count, setCount] = useState(1);
  const [Name, setName] = useState('');


  const handleCountUpdate = () => {
    setCount(Count + 1);
  }

  const handleInputChange = (e) => {
    setName(e.target.value);
  }

  //랜더링 될때마다 매번 실행됨
  useEffect(() => {
    console.log('랜더링 될때마다 매번 실행됨');
  },)

  //마운팅 + count 변화 될때마다 매번 실행됨
  useEffect(() => {
    console.log('count 변화');
  }, [Count])


  //마운팅 + Name 변화 될때마다 매번 실행됨
  useEffect(() => {
    console.log('Name 변화');
  }, [Name])


  useEffect(() => {
    console.log('마운팅 될 1번만 .....');
  }, [])

  return (
    <div>
      <button onClick={handleCountUpdate}>Update</button>
      <span>count : {Count}</span>
      <br /><br />

      <input type="text" value={Name} onChange={handleInputChange} />
      <span>{Name}</span>
    </div>
  )
}

export default Stu2And1

 

 

Stu2And2

useEffect  에서 return 함수는은 컴포넌트가 unmount 될때 종료 처리해 준다

import React from 'react'
import { useEffect } from 'react';

function Stu2And2() {


    useEffect(() => {
        const timer = setInterval(() => {
            console.log("타이머 돌아가는 중....");
        }, 1000);

        //다음 return 은 timer 컴포넌트가 unmount 될때 종료 처리해 준다
        return () => {
            clearInterval(timer);
            console.log("타이머가 종료되었습니다.");
        }
    }, [])


    return (
        <div>
            <span>타이머를 시작합니다. 콘솔을 보세요.!</span>
        </div>
    )
}

export default Stu2And2

 

 

 

 

 

3.useRef 완벽 정리 1# 변수 관리 

 

 

ref  DOM에 직접 접근하기

 DOM요소에 이름을 달아 직접 접근할 때

 

1)Stu3And1

import React, { useRef } from 'react'
import { useState } from 'react';

function Stu3And1() {

    const [Count, setCount] = useState(0);
    const countRef = useRef(0);


    console.log("랜더링 ....");

    const increaseCountState = () => {
        setCount(Count + 1);
    }

    const increaseCountRef = () => {
        countRef.current = countRef.current + 1;
        console.log("Ref  :", countRef.current);
    }

    return (
        <div>
            <p>State : {Count}</p>
            <p>Ref : {countRef.current}</p>
            <button onClick={increaseCountState}>State 올려</button>
            <button onClick={increaseCountRef}>Ref 올려</button>
        </div>
    )
}

export default Stu3And1

 

 

 

2)Stu3And2

 

ref 값을 유지 한다.

import React from 'react'
import { useState, useRef } from 'react';

function Stu3And2() {

    const [Renderer, setRenderer] = useState(0);
    const countRef = useRef(0);
    let countVar = 0;

    const doRendering = () => {
        setRenderer(Renderer + 1);
    }

    const increaseRef = () => {
        countRef.current = countRef.current + 1;
        console.log('ref : ', countRef.current);
    }

    const increaseVar = () => {
        countVar = countVar + 1;
        console.log('var : ', countVar);
    }

    const printResults = () => {
        console.log(`ref :  ${countRef.current} ,var :${countVar}`);
    }


    return (
        <div>
            <p>Ref : {countRef.current}</p>
            <p>Var : {countVar}</p>
            <button onClick={doRendering}>랜더!</button>
            <button onClick={increaseRef}>Ref 올려</button>
            <button onClick={increaseVar}>Var 올려</button>
            <button onClick={printResults}>Ref Var 값 출력</button>
        </div>
    )
}

export default Stu3And2



 

 

3)Stu3And3

import React from 'react'
import { useState, useRef, useEffect } from 'react';

function Stu3And3() {
    const [Count, setCount] = useState(1);
    const renderCount = useRef(1);

    useEffect(() => {
        renderCount.current = renderCount.current + 1;
        console.log("랜더링 수 : ", renderCount.current);
    })


    return (
        <div>
            <p>Count: {Count}</p>
            <button onClick={() => setCount(Count + 1)}>올려</button>
        </div>
    )
}

export default Stu3And3

 

 

 

 

 

 

4.useRef 완벽 정리 2# DOM 요소 접근 

 

Stu4And1

import React, { useEffect, useRef } from 'react'

function Stu4And1() {
    const inputRef = useRef("");

    useEffect(() => {
        inputRef.current.focus();
        console.log(inputRef.current);
    }, [])

    const login = () => {
        alert(`환영합니다. ${inputRef.current.value}!`);
        inputRef.current.focus();
    }

    return (
        <div>
            <input type="text" placeholder='username' ref={inputRef} />
            <button onClick={login}>로그인</button>
        </div >
    )
}
export default Stu4And1

 

 

 

 

 

 

 

 

5.useContext + Context API 

 

Redux vs React context api 어떤 경우에 사용 할 까?

Redux는 리액트 에서 많이 사용되는 state 관리 라이브러리 이고  context api는 리액트에서 기본으로 제공하는 state 관리 api 이다. 대부분에 경우 state management 라이브러리인 redux를 사용하는데 왜 그런지 알아보도록 하자. 

 

먼저 Redux와 context api에 특징에 대해서 알아보자 

Redux 

컴포넌트에 state를 prop으로 넘겨 줄 때 어느 컴포넌트 깊이와  상관 없이 넘겨줄 수 있다. 

 

만약에 컴포넌트 구조가 아래와 같이 되어 있는데 

/<Parent>
    <Child1>
      <Child2>
    	  <Child3></Child3>
      </Child2>
    </Child1>
  </Parent>
  
const child3Reducer = {
  candies: []
  iceCreams: []
}


const Child3 = () => {
  const iceCreams = useSelector(state => state.child3Reducer.iceCreams)
  return null

}

 

만약에 redux가 없다면 parent에서 state로 child3Data를 관리하고 Child1 Child2 Child3에게 prop으로 넘겨줘야 합니다. prop이 1-2개면 괜찮은데 prop이 많아지면 머리가 아파지고 또한 불필요한 rendering이 일어날 가능성이 크기 때문에 비효율 적일 수 있습니다. 하지만 코드에 보는 것 처럼 useSelector나 connect로 reducer에서 데이터를 바로 가져와서 사용할 수 있습니다.

 

연결된 state가 바뀌었을 때만 컴포넌트를 다시 랜더링 한다.

 위에 보이는것 처럼 child3Reducer에서 iceCreams state만 사용할 때 iceCreams가 바뀌었을 때만 다시 랜더링을 시킨다.

 

 

랜더링을 할지 안할지 코드를 통해서 컨트롤 할 수 있다.

함수형 컴포넌트를 사용할 때 memo로 컴포넌트를 감싸주면 불필요한 랜더링을 피할 수 있다. reselect 같은 라이브러리를 사용 할 수 도 있다.

 

Context api

  • 리덕스와 비슷하게 필요한 컴포넌트에서 바로 useContext를 사용해서 사용할 수 있다.
  • 코드를 통해서 랜더링을 할지 않할지 선택이 불가능 하다
  • 더 많은 코드를 써야된다. 
  • 완전히 간단한 앱에서만 사용하는 것을 추천한다. 

 

 

 

 

 

* 사용방법 

1. 다음과 같이 context.js 파일을 생성한다.

ThemeContext.js

import { createContext } from 'react'

export const ThemeContext = createContext(null);

 

2.  <ThemeContext.Provider   형태로 감싸주고  value 값에  변수 설정  한다.

<ThemeContext.Provider value={{ isDark, setIsDark }}>

import React from 'react'
import { useState } from 'react';
import Page from './Page';
import "../../../App.css"
import "./Section5.css";
import { ThemeContext } from './context/ThemeContext';
import { UserContext } from './context/UserContext';


function Stu5And1() {
    const [isDark, setIsDark] = useState(false);

    return (
        //  <Page isDark={isDark} setIsDark={setIsDark} />

        <UserContext.Provider value={'사용자'} >
            <ThemeContext.Provider value={{ isDark, setIsDark }}>
                <Page />
            </ThemeContext.Provider>
        </UserContext.Provider>
    )
}

export default Stu5And1

 

 

3. useContext 로 호출 한다.

    const { isDark, setIsDark } = useContext(ThemeContext);

Footer

import React, { useContext } from 'react'
import { ThemeContext } from './context/ThemeContext';

function Footer(porps) {

    const { isDark, setIsDark } = useContext(ThemeContext);


    const toggleTheme = () => {
        setIsDark(!isDark);
    }

    return (
        <footer className='footer'
            style={{ backgroundColor: isDark ? 'black' : 'lightgray' }}>


            <button className='button' onClick={toggleTheme}>Dark Mode</button>
        </footer>
    )
}

export default Footer

 

 

 

4. 기타 참조

 

Page.js

import React, { useContext } from 'react'
import Header from './Header';
import Content from './Content';
import Footer from './Footer';
import { ThemeContext } from './context/ThemeContext';

function Page({ isDark, setIsDark }) {

    const data = useContext(ThemeContext);
    console.log("data1 ", data);

    return (
        // <div className='page'>
        //     <Header isDark={isDark} />
        //     <Content isDark={isDark} />
        //     <Footer isDark={isDark} setIsDark={setIsDark} />
        // </div>

        <div className='page'>
            <Header />
            <Content />
            <Footer />
        </div>
    )
}

export default Page

 

 

Header.js

import React, { useContext } from 'react'
import { ThemeContext } from './context/ThemeContext';
import { UserContext } from './context/UserContext';

function Header() {

    const { isDark } = useContext(ThemeContext);
    const user = useContext(UserContext);

    return (
        <header className='header' style={{ backgroundColor: isDark ? 'black' : 'lightgray', color: isDark ? 'white' : 'black' }}>
            <h1>Welcome {user}!</h1>
        </header>
    )
}

export default Header

 

 

Content.js

import React, { useContext } from 'react'
import { ThemeContext } from './context/ThemeContext';

function Content() {

    const { isDark } = useContext(ThemeContext);

    return (
        <div className='header' style={{ backgroundColor: isDark ? 'black' : 'white', color: isDark ? 'white' : 'black' }}>

            <p>홍길동님,좋은 하루 되세요.</p>

        </div>
    )
}

export default Content

 

UserContext.js

import { createContext } from 'react';

export const UserContext = createContext(null);

 

 

 

 

 

 

 

6.useMemo 제대로 사용하기 

 

 

 

userMemo 를 사용 안할 경우 easyCalculate   호출할때도 hardCalculate  실행 된다.

import { useState } from 'react';


const hardCalculate = (number) => {
    console.log("어려운 계산!");
    for (let i = 0; i < 9999999; i++) { } //생각하는 시간
    return number + 10000;
}

const easyCalculate = (number) => {
    console.log("쉬운 계산!");
    return number + 1;
}

function Stu6And1() {
    const [hardNumber, setHardNumber] = useState(1);
    const [easyNumber, setEasyNumber] = useState(1);

    const hardSum = hardCalculate(hardNumber);
    const easySum = easyCalculate(easyNumber);

    return (
        <div>
            <h3>어려운 계산기</h3>
            <input type="number" value={hardNumber} onChange={(e) => setHardNumber(Number(e.target.value))} />
            <span>+10000 ={hardSum}</span>

            <br /><br />
            <h3>쉬운 계산기</h3>
            <input type="number" value={easyNumber} onChange={(e) => setEasyNumber(Number(e.target.value))} />
            <span>+10000 ={easySum}</span>

        </div>
    )
}

export default Stu6And1

 

====>

import { useMemo, useState } from 'react';


const hardCalculate = (number) => {
    console.log("어려운 계산!");
    for (let i = 0; i < 9999999; i++) { } //생각하는 시간
    return number + 10000;
}

const easyCalculate = (number) => {
    console.log("쉬운 계산!");
    return number + 1;
}

function Stu6And1() {
    const [hardNumber, setHardNumber] = useState(1);
    const [easyNumber, setEasyNumber] = useState(1);

    //const hardSum = hardCalculate(hardNumber);
    const hardSum = useMemo(() => {
        return hardCalculate(hardNumber);
    }, [hardNumber]);

    const easySum = easyCalculate(easyNumber);

    return (
        <div>
            <h3>어려운 계산기</h3>
            <input type="number" value={hardNumber} onChange={(e) => setHardNumber(Number(e.target.value))} />
            <span>+10000 ={hardSum}</span>

            <br /><br />
            <h3>쉬운 계산기</h3>
            <input type="number" value={easyNumber} onChange={(e) => setEasyNumber(Number(e.target.value))} />
            <span>+10000 ={easySum}</span>

        </div>
    )
}

export default Stu6And1

 

 

★객체로  useEffect  적용시에    userMemo  사용 할것.

 

import { useEffect, useState, useMemo } from 'react';


function Stu6And2() {
    const [number, setNumer] = useState(0);
    const [isKorea, setIsKorea] = useState(true);

    // const location = isKorea ? '한국' : '외국';

    // const location = {
    //     country: isKorea ? '한국' : '외국'
    // }

    const location = useMemo(() => {
        return {
            country: isKorea ? '한국' : '외국'
        }
    }, [isKorea]);


    useEffect(() => {
        console.log("useEffect 호출");
    }, [location]);

    return (
        <div>
            <h2>하루에 몇끼 먹어요?</h2>
            <input
                type="number"
                value={number}
                onChange={(e) => setNumer(e.target.value)}
            />

            <hr />
            <h2>어느 나라에 있어요?</h2>
            {/* <p>나라: {location}</p> */}
            <p>나라: {location.country}</p>
            <button onClick={() => setIsKorea(!isKorea)}>비행기 타자</button>
        </div>
    )
}

export default Stu6And2

 

 

 

 

 

 

 

7. useCallback 짱 쉬운 강의 

 

 

 

 

useCallback 

useCallback은 특정 함수를 새로 만들지 않고 재사용하고 싶을 때 사용.

useCallback은 React.memo와 함께 자식 컴포넌트의 불필요한 렌더링을 최적화할 수  있다.

 

왜 useCallback을 사용해야 할까요?

현재 하위 컴포넌트에 전달하는 콜백 함수가 inline 함수로 사용되거나, 컴포넌트 내에서 함수를 생성하고 있다면 새로운 함수가 만들어지게 됩니다. 예를 들어보자면, number 안에 someFunction 함수들은 컴포넌트가 리렌더링 될 때 마다 새로 만들어지게 됩니다.

함수를 재 선언 하는것은 CPU, 큰 메모리도 차지하지 않지만, 한번 만든 함수를 재 사용하고, 필요할 때만 재 생성 하는것은 중요합니다. 

 

 

예1)

 

 

 

import React, { useCallback } from 'react'
import { useState, useEffect } from 'react';

function Stu7And1() {

    const [number, setNumber] = useState(0);
    const [toggle, setToggle] = useState(false);

    //1.useCallback 을 사용하지 않고 다음과 같은 함수 사용시에 toggle 버튼 클릭시
    // someFunction 함수도 호출된다.
    // const someFunction = () => {
    //     console.log(`someFunc : number : ${number}`);
    //     return;
    // };

    const someFunction = useCallback(() => {
        console.log(`someFunc : number : ${number}`);
        return;
    }, [number]);


    useEffect(() => {
        console.log('someFunction 이 변경되었습니다.');
    }, [someFunction])


    return (
        <div>
            <input type="number"
                value={number}
                onChange={(e) => setNumber(e.target.value)}
            />
            <button onClick={() => setToggle(!toggle)}>{toggle.toString()}</button>
            <br />
            <button onClick={someFunction}>Call SomeFunce</button>
        </div>
    )
}

export default Stu7And1

 

 

 

 

예2) 

 

 

Stu7And2.js

import { useState, useCallback } from 'react';
import Box from './Box';


function Stu7And2() {

    const [size, setSize] = useState(100);
    const [isDark, setIsDark] = useState(false);

    // const createBoxStyle = () => {
    //     return {
    //         backgroundColor: 'pink',
    //         width: `${size}px`,
    //         height: `${size}px`
    //     }
    // }


    const createBoxStyle = useCallback(() => {
        return {
            backgroundColor: 'pink',
            width: `${size}px`,
            height: `${size}px`
        }
    }, [size]);



    return (
        <div style={{ background: isDark ? "black" : "white" }}>
            <input
                type="number"
                value={size}
                onChange={(e) => setSize(e.target.value)}
            />

            <button onClick={() => setIsDark(!isDark)}>Change Theme</button>
            <Box createBoxStyle={createBoxStyle} />
        </div>
    )
}

export default Stu7And2

 

 

Box.js

import { useEffect, useState } from 'react';

function Box({ createBoxStyle }) {
    const [style, setStyle] = useState({});

    useEffect(() => {
        console.log("박스 키우기11");
        setStyle(createBoxStyle());

    }, [createBoxStyle]);

    return (
        <div style={style}></div>
    )
}

export default Box

 

 

 

 

 

 

 

 

8. useReducer 확실히 정리해드려요

 

 

 

 

 

 

 

예1)  

Stu8And1.js

 

 

import React, { useReducer, useState } from 'react'


//reducer - state를 업데이트 하는 역할 (은행)
//dispatch - state 업데이트를 위한 요구
//action -요구의 내용
const ACTION_TYPES = {
    deposit: 'deposit',
    withdraw: 'withdraw'
}
const reducer = (state, action) => {
    console.log('reducer 가 일을 합니다.!', state, action);
    switch (action.type) {
        case ACTION_TYPES.deposit:
            return state + action.payload;

        case ACTION_TYPES.withdraw:
            return state - action.payload;
        default:
            return state;
    }
};


function Stu8And1() {
    const [number, setNumber] = useState(0);
    const [money, dispatch] = useReducer(reducer, 0);


    return (
        <div>
            <h2>useRducer 은행에 오신것을 환영합니다.</h2>
            <p>잔고: {money}원</p>

            <input type="number"
                value={number}
                onChange={(e) => setNumber(parseInt(e.target.value))}
                step="1000" />
            <button onClick={() => { dispatch({ type: 'deposit', payload: number }); }}>예금</button>
            <button onClick={() => { dispatch({ type: 'withdraw', payload: number }); }} >출금</button>
        </div>
    )
}

export default Stu8And1

 

 

 

 

 

예2) 

Student.js

import React from 'react'

function Student({ name, dispatch, id, isHere }) {
    return (
        <div>
            <br />
            <p>
                <span style={{
                    textDecoration: isHere ? 'line-through' : 'none',
                    color: isHere ? 'gray' : 'black'
                }}

                    onClick={() => dispatch({ type: 'mark-student', payload: { id } })}
                >
                    {name}
                </span>

                <button onClick={() => {
                    dispatch({ type: 'delete-student', payload: { id } })
                }}>삭제</button>
            </p>
        </div>
    )
}

export default Student

 

 

 

 Stu8And2.js

import React from 'react'
import { useState, useReducer } from 'react';
import Student from './Student';

const ACTION_TYPES = {
    ADD_STUDENT: 'add-student',
    DELETE_STUDENT: 'delete-student',
    MARK_STUDENT: 'mark-student'
}
const reducer = (state, action) => {

    switch (action.type) {
        case ACTION_TYPES.ADD_STUDENT:
            console.log("학생 추가: ", state, action);
            const newStudent = {
                id: Date.now(),
                name: action.payload.name,
                isHere: false
            }
            return {
                count: state.count + 1,
                students: [...state.students, newStudent]
            };

        case ACTION_TYPES.DELETE_STUDENT:
            console.log("학생 삭제: ", state, action);
            return {
                count: state.count - 1,
                students: state.students.filter((student) => student.id !== action.payload.id)
            }

        case ACTION_TYPES.MARK_STUDENT  :
            return {
                count: state.count,
                students: state.students.map((student) => {
                    if (student.id === action.payload.id) {
                        return { ...student, isHere: !student.isHere }
                    }
                    return student;
                })
            }
        default:
            return state;
    }
};

const initialState = {
    count: 0,
    students: []
}

function Stu8And2() {
    const [name, setName] = useState('');
    const [studentInfo, dispatch] = useReducer(reducer, initialState);

    return (
        <div>
            <h1>출석부</h1>
            <p>총 학생 수 : {studentInfo.count}</p>
            <input
                type="text"
                placeholder='이름을 입력해주세요.'
                value={name}
                onChange={(e) => setName(e.target.value)}
            />

            <button onClick={() => dispatch({ type: 'add-student', payload: { name } })}>추가</button>


            {studentInfo.students.map(student => {
                return (<Student key={student.id} name={student.name} dispatch={dispatch} id={student.id} isHere={student.isHere} />)
            })}
        </div>
    )
}

export default Stu8And2;

 

 

 

 

 

 

 

 

 

 

 

 

9.React.memo로 컴포넌트 최적화하기 (ft. useMemo, useCallback)

 

 

예1)

Stu9And1

import React, { useState } from 'react'
import Child from './Child';

function Stu9And1() {
    const [parentAge, setParentAge] = useState(0);
    const [childAge, setChildAge] = useState(0);

    const incrementParentAge = () => {
        setParentAge(parentAge + 1);
    }

    const incrementChildAge = () => {
        setChildAge(childAge + 1);
    }

    console.log('부모 컴포넌트가 랜더링 되었어요.');

    return (
        <div>
            <h1>부모</h1>
            <p>age : {parentAge}</p>
            <button onClick={incrementParentAge}   >부모 나이 증가</button>
            <button onClick={incrementChildAge}   >자식 나이 증가</button>
            <Child name={'홍길동'} age={childAge} />
        </div>
    )
}

export default Stu9And1

 

 

 

memo 사용법은  export  시에  memo(Child) 로 감싸주기만 하면된다.

Child  .js

import React, { memo } from 'react'

function Child({ name, age }) {

    console.log('자녀도 랜더링 되었어요.');
    return (
        <div style={{ border: '2px solid powderblue', padding: '10px' }}>
            <h3>자녀</h3>
            <p>name:{name}</p>
            <p>age : {age}살</p>
        </div>
    )
}

export default memo(Child);

 

 

 

 

예2)memo, useMemo 과 함께 사용

Stu9And2.js

import React, { useMemo, useState } from 'react'
import Child2 from './Child2';

function Stu9And2() {
    const [parentAge, setParentAge] = useState(0);

    const incrementParentAge = () => {
        setParentAge(parentAge + 1);
    }

    console.log('부모 컴포넌트가 랜더링 되었어요.');

    const name = useMemo(() => {
        return {
            lastName: "홍",
            firstName: "길동"
        }
    }, []);

    return (
        <div>
            <h1>부모</h1>
            <p>age : {parentAge}</p>
            <button onClick={incrementParentAge}   >부모 나이 증가</button>
            <Child2 name={name} />


        </div>
    )
}

export default Stu9And2

Child2.js

import React, { memo } from 'react'

function Child2({ name }) {

    console.log('자녀도 랜더링 되었어요.');
    return (
        <div style={{ border: '2px solid powderblue', padding: '10px' }}>
            <h3>자녀</h3>
            <p>성:{name.lastName}</p>
            <p>이름:{name.firstName}</p>
        </div>
    )
}

export default memo(Child2);

 

 

 

 

예3)memo,  useCallback 과 함께 사용

Stu9And3

import React, { useState, useCallback } from 'react'
import Child3 from './Child3';

function Stu9And3() {
    const [parentAge, setParentAge] = useState(0);

    const incrementParentAge = () => {
        setParentAge(parentAge + 1);
    }

    console.log('부모 컴포넌트가 랜더링 되었어요.');

    const tellMe = useCallback(() => {
        console.log('길동아 사랑해 ');
    }, []);

    return (
        <div>
            <h1>부모</h1>
            <p>age : {parentAge}</p>
            <button onClick={incrementParentAge}   >부모 나이 증가</button>
            <Child3 name={'홍길동'} tellMe={tellMe} />
        </div>
    )
}

export default Stu9And3

 

Child3

import React, { memo } from 'react'

function Child3({ name, tellMe }) {

    console.log('자녀도 랜더링 되었어요.');
    return (
        <div style={{ border: '2px solid powderblue', padding: '10px' }}>
            <h3>자녀</h3>
            <p>이름:{name}</p>
            <button onClick={tellMe}>엄마 나 사랑해?</button>
        </div>
    )
}

export default memo(Child3);

 

 

 

 

 

 

 

 

 

 

 

10.Custom Hooks 커스텀 훅 

 

 

예1)

import { useInput } from './useInput';

function Stu10And1() {
    const [inputValue, handleChange] = useInput("안녕");
    const [inputValue2, handleChange2] = useInput("123");

    const handleSubmit = () => {
        alert(inputValue);
    }

    return (
        <div>
            <h1>useInput</h1>
            <input value={inputValue} onChange={handleChange} />
            <input value={inputValue2} onChange={handleChange2} />
            <button onClick={handleSubmit}>확인</button>
        </div>
    )
}

export default Stu10And1

 

custom hooks input

import { useState } from 'react';

export function useInput(initialValue) {
    const [inputValue, setInputValue] = useState(initialValue);

    const handleChange = (e) => {
        setInputValue(e.target.value);
    };

    return [inputValue, handleChange];

}

 

 

 

 

 

예2)

Stu10And1

import { useInput } from './useInput';


function displyMessage(message) {
    alert(message);
}

function Stu10And1() {
    const [inputValue, handleChange, handleSubmit] = useInput("안녕", displyMessage);

    return (
        <div>
            <h1>useInput</h1>
            <input value={inputValue} onChange={handleChange} />
            <button onClick={handleSubmit}>확인</button>
        </div>
    )
}

export default Stu10And1

 

custom hooks useInput

import { useState } from 'react';

export function useInput(initialValue, submitAction) {
    const [inputValue, setInputValue] = useState(initialValue);

    const handleChange = (e) => {
        setInputValue(e.target.value);

    };

    const handleSubmit = () => {
        setInputValue("");
        submitAction(inputValue);
    }

    return [inputValue, handleChange, handleSubmit];

}

 

 

 

 

 

예3)

 

Stu10And2

import { useFetch } from './useFetch';

let baseUrl = "https://jsonplaceholder.typicode.com";

function Stu10And2() {

    const { data, fetchUrl } = useFetch(baseUrl, "users");
    const { data: userData } = useFetch(baseUrl, "users");
    const { data: postData } = useFetch(baseUrl, "posts");

    return (
        <div>
            <h1>useFetch</h1>
            <button onClick={() => fetchUrl('users')}>Users</button>
            <button onClick={() => fetchUrl('posts')}>Posts</button>
            <button onClick={() => fetchUrl('todos')}>Todos</button>
            <br />
            <textarea style={{ width: 300, height: 300 }} value={data && JSON.stringify(data, null, 2)}> </textarea>

            <br /><br />
            <h1>User</h1>
            {userData && <pre> {JSON.stringify(userData[0], null, 2)}</pre>}

            <br /><br />
            <h1>Post</h1>
            {postData && <pre> {JSON.stringify(postData[0], null, 2)}</pre>}

        </div>
    )
}

export default Stu10And2;

 

custom hooks useFetch

import { useState, useEffect } from 'react';

export function useFetch(baseUrl, initialType) {

    const [data, setData] = useState(null);

    const fetchUrl = (type) => {
        fetch(baseUrl + "/" + type)
            .then((res) => res.json())
            .then((res) => setData(res));
    }

    useEffect(() => {
        fetchUrl(initialType);
    }, []);

    return { data, fetchUrl };
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

지붕잇기를 성기게 하면 비가 새듯이, 마음을 조심하지 않으면 탐욕이 곧 마음을 뚫고 들어온다. -법구경

댓글 ( 4)

댓글 남기기

작성