Yeom.log 2021. 5. 2. 00:23
λ°˜μ‘ν˜•

hook 을 배우기 μœ„ν•΄μ„œ npx create-react-app hooks-tuotrial 을 ν•΄μ£Όμ„Έμš”!

 

1. useState

useStateλŠ” κ°€μž₯ 기본적인 Hook μœΌλ‘œμ„œ, ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈμ—μ„œλ„ 가변적인 μƒνƒœλ₯Ό μ§€λ‹ˆκ³ 

μžˆμ„ 수 있게 ν•΄μ€λ‹ˆλ‹€. λ§Œμ•½μ— ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈμ—μ„œ μƒνƒœλ₯Ό 관리해야 λ˜λŠ” 일이 λ°œμƒν•œλ‹€λ©΄

이 Hook 을 μ‚¬μš©ν•˜μ‹œλ©΄ λ©λ‹ˆλ‹€.

 

ν•œλ²ˆ 이 κΈ°λŠ₯을 μ‚¬μš©ν•΄μ„œ 숫자 μΉ΄μš΄ν„°λ₯Ό κ΅¬ν˜„ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€. 

 

src 디렉터리에 Counter.js νŒŒμΌμ„ μƒμ„±ν•˜κ³  λ‹€μŒ μ½”λ“œλ₯Ό μž…λ ₯ν•΄λ³΄μ„Έμš”

 

Counter.js

import React, { useState } from 'react';

const Counter = () => {
  const [value, setValue] = useState(0);

  return (
    <div>
      <p>
        ν˜„μž¬ μΉ΄μš΄ν„° 값은 <b>{value}</b> μž…λ‹ˆλ‹€.
      </p>
      <button onClick={() => setValue(value + 1)}>+1</button>
      <button onClick={() => setValue(value - 1)}>-1</button>
    </div>
  );
};

export default Counter;

 

 

Counter μ»΄ν¬λ„ŒνŠΈλ₯Ό λ Œλ”λ§

 

App.js

import React from 'react';
import './App.css';
import Counter from './Counter';

const App = () => {
  return <Counter />;
};

export default App;

 

npm start

 

1.1 useState λ₯Ό μ—¬λŸ¬λ²ˆ μ‚¬μš©ν•˜κΈ°

 

ν•˜λ‚˜μ˜ useState ν•¨μˆ˜λŠ” ν•˜λ‚˜μ˜ μƒνƒœ κ°’λ§Œ 관리λ₯Ό ν•  수 있기 λ•Œλ¬Έμ— λ§Œμ•½μ— μ»΄ν¬λ„ŒνŠΈμ—μ„œ

관리해야 ν•  μƒνƒœκ°€ μ—¬λŸ¬ 개라면 useState λ₯Ό μ—¬λŸ¬λ²ˆ μ‚¬μš©ν•˜λ©΄ λœλ‹€.

 

src 디렉터리에 Info.js νŒŒμΌμ„ μƒμ„±ν•˜κ³  λ‹€μŒμ˜ μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ„Έμš”

 

Info.js

import React, { useState } from 'react';

const Info = () => {
  const [name, setName] = useState('');
  const [nickname, setNickname] = useState('');

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

  const onChangeNickname = e => {
    setNickname(e.target.value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={onChangeName} />
        <input value={nickname} onChange={onChangeNickname} />
      </div>
      <div>
        <div>
          <b>이름: </b> {name}
        </div>
        <div>
          <b>λ‹‰λ„€μž„: </b>
          {nickname}
        </div>
      </div>
    </div>
  );
};

export default Info;

 

App μ»΄ν¬λ„ŒνŠΈμ—μ„œ λ Œλ”λ§

 

App.js

import React from 'react';
import './App.css';
import Info from './Info';

const App = () => {
  return <Info />;
};

export default App;

 

Info.js


2. useEffect

λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈκ°€ λ Œλ”λ§ 될 λ•Œλ§ˆλ‹€ νŠΉμ • μž‘μ—…μ„ μˆ˜ν–‰ν•˜λ„λ‘ μ„€μ • ν•  수 μžˆλŠ”

Hook μž…λ‹ˆλ‹€. ν΄λž˜μŠ€ν˜• μ»΄ν¬λ„ŒνŠΈμ˜ componentDidMount 와 componentDidUpdate λ₯Ό 

ν•©μΉ­ ν˜•νƒœλ‘œ 보아도 무방

 

Info μ»΄ν¬λ„ŒνŠΈμ— useEffect λ₯Ό 적용

 

Info.js

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

const Info = () => {
  const [name, setName] = useState('');
  const [nickname, setNickname] = useState('');
  useEffect(() => {
    console.log('λ Œλ”λ§μ΄ μ™„λ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€!');
    console.log({
      name,
      nickname,
    });
  });

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

  const onChangeNickname = e => {
    setNickname(e.target.value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={onChangeName} />
        <input value={nickname} onChange={onChangeNickname} />
      </div>
      <div>
        <div>
          <b>이름: </b> {name}
        </div>
        <div>
          <b>λ‹‰λ„€μž„: </b>
          {nickname}
        </div>
      </div>
    </div>
  );
};

export default Info;

 

Info.js
useEffect

 

2.1 마운트 될 λ•Œλ§Œ μ‹€ν–‰ν•˜κ³  싢을 λ•Œ

λ§Œμ•½ useEffect μ—μ„œ μ„€μ •ν•œ ν•¨μˆ˜κ°€ μ»΄ν¬λ„ŒνŠΈκ°€ 화면에 κ°€μž₯ 처음 λ Œλ”λ§ 될 λ•Œλ§Œ μ‹€ν–‰λ˜κ³  

μ—…λ°μ΄νŠΈ ν•  κ²½μš°μ—λŠ” μ‹€ν–‰ ν•  ν•„μš”κ°€ μ—†λŠ” κ²½μš°μ—” ν•¨μˆ˜μ˜ λ‘λ²ˆμ§Έ νŒŒλΌλ―Έν„°λ‘œ λΉ„μ–΄μžˆλŠ”

배열을 λ„£μ–΄μ£Όμ‹œλ©΄ λ©λ‹ˆλ‹€.

 

Info.js - useEffect

useEffect(() => {
    console.log('마운트 될 λ•Œλ§Œ μ‹€ν–‰λ©λ‹ˆλ‹€.');
  }, []);

 

console

 

2.2 νŠΉμ • 값이 μ—…λ°μ΄νŠΈ 될 λ•Œλ§Œ μ‹€ν–‰ν•˜κ³  싢을 λ•Œ

useEffect λ₯Ό μ‚¬μš© ν•  λ•Œ νŠΉμ • 값이 변경이 될 λ•Œλ§Œ ν˜ΈμΆœν•˜κ²Œ ν•˜κ³  싢을 κ²½μš°λ„ μžˆμ„

κ²ƒμž…λ‹ˆλ‹€.

 

Info.js - useEffect

 useEffect(() => {
    console.log(name);
  }, [name]);

 

React만 μ½˜μ†”μ— μ°νžˆλŠ”κ²ƒμ„ λ³Ό 수 μžˆλ‹€.

 

 

λ°°μ—΄ μ•ˆμ—λŠ” useState λ₯Ό 톡해 κ΄€λ¦¬ν•˜κ³  μžˆλŠ” μƒνƒœλ₯Ό λ„£μ–΄μ€˜λ„ 되고 , props둜 전달받은

값을 넣어주어도 λ©λ‹ˆλ‹€.

 

2.3 뒷정리 ν•¨μˆ˜

λ§Œμ•½ μ»΄ν¬λ„ŒνŠΈκ°€ μ–Έλ§ˆμš΄νŠΈλ˜κΈ° μ „μ΄λ‚˜, μ—…λ°μ΄νŠΈ 되기 직전에 μ–΄λ– ν•œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜κ³  

μ‹Άλ‹€λ©΄ useEffect μ—μ„œ 뒷정리(cleanup) ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•΄μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.

 

Info.js - useEffect

 

useEffect(() => {
    console.log('effect');
    console.log(name);
    return () => {
      console.log('cleanup');
      console.log(name);
    };
  });

 

App.js

import React, { useState } from 'react';
import './App.css';
import Info from './Info';

const App = () => {
  const [visible, setVisible] = useState(false);
  return (
    <div>
      <button
        onClick={() => {
          setVisible(!visible);
        }}
      >
        {visible ? '숨기기' : '보이기'}
      </button>
      <hr />
      {visible && <Info />}
    </div>
  );
};

export default App;

 

μƒλ‹¨μ˜ 보이기 / 숨기기 λ²„νŠΌμ„ λˆŒλŸ¬λ³΄μ„Έμš”!

λ§Œμ•½μ— , 였직 μ–Έλ§ˆμš΄νŠΈ 될 λ•Œλ§Œ 뒷정리 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κ³  μ‹ΆμœΌμ‹œλ‹€λ©΄ useEffect ν•¨μˆ˜μ˜

λ‘λ²ˆμ§Έ νŒŒλΌλ―Έν„°μ— λΉ„μ–΄μžˆλŠ” 배열을 λ„£μœΌμ‹œλ©΄ λ©λ‹ˆλ‹€.

 

Info.js - useEffect

  useEffect(() => {
    console.log('effect');
    console.log(name);
    return () => {
      console.log('cleanup');
      console.log(name);
    };
  });

3. useContext

이 Hook 을 μ‚¬μš©ν•˜λ©΄ ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈμ—μ„œ Context λ₯Ό 보닀 더 μ‰½κ²Œ μ‚¬μš© ν•  수 μžˆμŠ΅λ‹ˆλ‹€

 

src 디렉터리에 ContextSample.js μ΄λΌλŠ” μ»΄ν¬λ„ŒνŠΈλ₯Ό λ§Œλ“€μ–΄λ³΄μ„Έμš”

 

ContextSample.js

import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('black');
const ContextSample = () => {
  const theme = useContext(ThemeContext);
  const style = {
    width: '24px',
    height: '24px',
    background: theme,
  };
  return <div style={style} />;
};

export default ContextSample;

 

App.js

import React from 'react';
import ContextSample from './ContextSample';

const App = () => {
  return <ContextSample />;
};

export default App;

 

 

λ Œλ”λ§


4. useReducer

useReducer λŠ” useState 보닀 μ»΄ν¬λ„ŒνŠΈμ—μ„œ 더 λ‹€μ–‘ν•œ 상황에 따라 λ‹€μ–‘ν•œ μƒνƒœλ₯Ό λ‹€λ₯Έ

κ°’μœΌλ‘œ μ—…λ°μ΄νŠΈν•΄μ£Όκ³  싢을 μ‚¬μš©ν•˜λŠ” Hook. 

 

ReducerλŠ” ν˜„μž¬ μƒνƒœμ™€, μ—…λ°μ΄νŠΈλ₯Ό μœ„ν•΄ ν•„μš”ν•œ 정보λ₯Ό 담은 μ•‘μ…˜(action) 값을 전달 λ°›μ•„

μƒˆλ‘œμš΄ μƒνƒœλ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€. λ¦¬λ“€μ„œ ν•¨μˆ˜μ—μ„œ μƒˆλ‘œμš΄ μƒνƒœλ₯Ό λ§Œλ“€ λ•ŒλŠ” κΌ­

λΆˆλ³€μ„±μ„ μ§€μΌœμ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.

 

4.1 μΉ΄μš΄ν„° κ΅¬ν˜„ν•˜κΈ°

λ¨Όμ €, 기쑴의 Counter μ»΄ν¬λ„ŒνŠΈλ₯Ό useReducer λ₯Ό μ‚¬μš©ν•˜μ—¬ λ‹€μ‹œ κ΅¬ν˜„

 

Counter.js

import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { value: state.value + 1 };
    case 'DECREMENT':
      return { value: state.value - 1 };
    default:
      return state;
  }
}

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, { value: 0 });

  return (
    <div>
      <p>
        ν˜„μž¬ μΉ΄μš΄ν„° 값은 <b>{state.value}</b> μž…λ‹ˆλ‹€.
      </p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>-1</button>
    </div>
  );
};

export default Counter;

 

useReducer 의 첫번째 νŒŒλΌλ―Έν„°λŠ” λ¦¬λ“€μ„œ ν•¨μˆ˜, 그리도 λ‘λ²ˆμ§Έ νŒŒλΌλ―Έν„°λŠ” ν•΄λ‹Ή λ¦¬λ“€μ„œμ˜

κΈ°λ³Έ 값을 λ„£μ–΄μ€λ‹ˆλ‹€. 이 Hook을 μ‚¬μš© ν–ˆμ„ λ•Œμ—λŠ” state κ°’κ³Ό dispatch ν•¨μˆ˜λ₯Ό λ°›μ•„μ˜€κ²Œ

λ˜λŠ”λ°μš”, μ—¬κΈ°μ„œ state λŠ” ν˜„μž¬ κ°€λ₯΄ν‚€κ³  μžˆλŠ” μƒνƒœκ³ , dispatch λŠ” μ•‘μ…˜μ„ λ°œμƒμ‹œν‚€λŠ”

ν•¨μˆ˜μž…λ‹ˆλ‹€. dispatch(action) 와 같은 ν˜•νƒœλ‘œ, ν•¨μˆ˜ μ•ˆμ— νŒŒλΌλ―Έν„°λ‘œ μ•‘μ…˜ 값을 λ„£μ–΄μ£Όλ©΄

λ¦¬λ“€μ„œ ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜λŠ” κ΅¬μ‘°μž…λ‹ˆλ‹€.

 

useRedcuer 을 μ‚¬μš©ν–ˆμ„ λ•Œμ˜ κ°€μž₯ 큰 μž₯점은 μ»΄ν¬λ„ŒνŠΈ μ—…λ°μ΄νŠΈ λ‘œμ§μ„ μ»΄ν¬λ„ŒνŠΈ λ°”κΉ₯으둜

λΉΌλ‚Ό 수 μžˆλ‹€λŠ” 점 μž…λ‹ˆλ‹€.

 

App.js

import React from 'react';
import Counter from './Counter';

const App = () => {
  return <Counter />;
};

export default App;

 

4.2 인풋 μƒνƒœ κ΄€λ¦¬ν•˜κΈ°

μ΄λ²ˆμ—λŠ” useReducer λ₯Ό μ‚¬μš©ν•˜μ—¬ Info μ»΄ν¬λ„ŒνŠΈμ—μ„œ 인풋 μƒνƒœλ₯Ό κ΄€λ¦¬ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

κΈ°μ‘΄μ—λŠ” 인풋이 μ—¬λŸ¬ κ°œμ—¬μ„œ useState λ₯Ό μ—¬λŸ¬λ²ˆ μ‚¬μš©ν–ˆλŠ”λ°μš”, useReducer λ₯Ό μ‚¬μš©ν•œλ‹€λ©΄

μš°λ¦¬κ°€ 기쑴에 ν΄λž˜μŠ€ν˜• μ»΄ν¬λ„ŒνŠΈμ—μ„œ input νƒœκ·Έμ— name 값을 ν• λ‹Ήν•˜κ³  e.target.name 을 

μ°Έμ‘°ν•˜μ—¬ setState λ₯Ό ν•΄μ€€ 것과 μœ μ‚¬ν•œ λ°©μ‹μœΌλ‘œ μž‘μ—…μ„ 처리 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

Info.js

import React, { useReducer } from 'react';

function reducer(state, action) {
  return {
    ...state,
    [action.name]: action.value,
  };
}

const Info = () => {
  const [state, dispatch] = useReducer(reducer, {
    name: '',
    nickname: '',
  });
  const { name, nickname } = state;
  const onChange = e => {
    dispatch(e.target);
  };

  return (
    <div>
      <div>
        <input name="name" value={name} onChange={onChange} />
        <input name="nickname" value={nickname} onChange={onChange} />
      </div>
      <div>
        <div>
          <b>이름:</b> {name}
        </div>
        <div>
          <b>λ‹‰λ„€μž„: </b>
          {nickname}
        </div>
      </div>
    </div>
  );
};

export default Info;

 

App.js

import React from 'react';
import Info from './Info';

const App = () => {
  return <Info />;
};

export default App;

5. useMemo

useMemo λ₯Ό μ‚¬μš©ν•˜λ©΄ ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈ λ‚΄λΆ€μ—μ„œ λ°œμƒν•˜λŠ” 연산을 μ΅œμ ν™” ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ¨Όμ € λ¦¬μŠ€νŠΈμ— μˆ«μžλ“€μ„ μΆ”κ°€ν•˜λ©΄ ν•΄λ‹Ή μˆ«μžλ“€μ˜ 평균을 λ‚˜νƒ€λ‚΄λŠ” ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈλ₯Ό

μž‘μƒν•΄ λ΄…μ‹œλ‹€.

 

src 디렉터리에 Averge.js νŒŒμΌμ„ μƒμ„±ν•˜μ„Έμš”

 

Average.js

import React, { useState } from 'react';

const getAverage = numbers => {
  console.log('평균값 계산쀑..');
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
};

const Average = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState('');

  const onChange = e => {
    setNumber(e.target.value);
  };
  const onInsert = e => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber('');
  };

  return (
    <div>
      <input value={number} onChange={onchange} />
      <button onClick={onInsert}>등둝</button>
      <ul>
        {list.map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      <div>
        <b>평균 κ°’:</b> {getAverage(list)}
      </div>
    </div>
  );
};

export default Average;

 

App.js

import React from 'react';
import Average from './Average';

const App = () => {
  return <Average />;
};

export default App;

 

평균 값은 잘 보여지고 μžˆλŠ”λ°, 숫자λ₯Ό 등둝할 λ•ŒλΏλ§Œ μ•„λ‹ˆλΌ 인풋 λ‚΄μš©μ΄ μˆ˜μ • 될 λ•Œλ„

μš°λ¦¬κ°€ λ§Œλ“  getAverage ν•¨μˆ˜κ°€ 호좜되고 μžˆλŠ”κ²ƒμ„ 확인 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 인풋 λ‚΄μš©μ΄ λ°”λ€”

땐 평균 값을 λ‹€μ‹œ 계산 ν•  ν•„μš”κ°€ μ—†λŠ”λ°, μ΄λ ‡κ²Œ λ Œλ”λ§ ν•  λ•Œλ§ˆλ‹€ 계산을 ν•˜λŠ” 것은 λ‚­λΉ„.

 

useMemo Hook 을 μ‚¬μš©ν•˜λ©΄ μ΄λŸ¬ν•œ μž‘μ—…μ„ μ΅œμ ν™” ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ Œλ”λ§ ν•˜λŠ” κ³Όμ •μ—μ„œ 

νŠΉμ • 값이 λ°”λ€Œμ—ˆμ„ λ•Œλ§Œ 연산을 μ‹€ν–‰ν•˜κ³  λ§Œμ•½μ— μ›ν•˜λŠ” 값이 바뀐 것이 μ•„λ‹ˆλΌλ©΄ 이전에

μ—°μ‚°ν–ˆλ˜ κ²°κ³Όλ₯Ό λ‹€μ‹œ μ‚¬μš©ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.

 

Average.js

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

const getAverage = numbers => {
  console.log('평균값 계산쀑..');
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
};

const Average = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState('');

  const onChange = e => {
    setNumber(e.target.value);
  };
  const onInsert = e => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber('');
  };

  const avg = useMemo(() => getAverage(list), [list]);

  return (
    <div>
      <input value={number} onChange={onChange} />
      <button onClick={onInsert}>등둝</button>
      <ul>
        {list.map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      <div>
        <b>평균 κ°’:</b> {avg}
      </div>
    </div>
  );
};

export default Average;

list λ°°μ—΄μ˜ λ‚΄μš©μ΄ λ°”λ€” λ•Œμ—λ§Œ getAverage ν•¨μˆ˜κ°€ 호좜


6. useCallback

useCallback 은 useMemo 와 μƒλ‹Ήνžˆ λΉ„μŠ·ν•œ ν•¨μˆ˜μž…λ‹ˆλ‹€. 주둜 λ Œλ”λ§ μ„±λŠ₯을 μ΅œμ ν™”ν•΄μ•Ό

ν•˜λŠ” μƒν™©μ—μ„œ μ‚¬μš©ν•˜λŠ”λ°μš”, 이 Hook 을 μ‚¬μš©ν•˜λ©΄ 이벀트 ν•Έλ“€λŸ¬ ν•¨μˆ˜λ₯Ό ν•„μš”ν•  λ•Œλ§Œ 생성

ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μš°λ¦¬κ°€ 방금 κ΅¬ν˜„ν•œ Average μ»΄ν¬λ„ŒνŠΈλ₯Ό 보면, onChange 와 onInsert λΌλŠ” ν•¨μˆ˜λ₯Ό

μ„ μ–Έν•΄μ£Όμ—ˆμŠ΅λ‹ˆλ‹€. μ΄λ ‡κ²Œ 선언을 ν•˜κ²Œ 되면 μ»΄ν¬λ„ŒνŠΈκ°€ λ¦¬λ Œλ”λ§ 될 λ•Œλ§ˆλ‹€ 이 ν•¨μˆ˜λ“€μ΄

μƒˆλ‘œ μƒμ„±λ©λ‹ˆλ‹€. λŒ€λΆ€λΆ„μ˜ κ²½μš°μ—λŠ” μ΄λŸ¬ν•œ 방식이 λ¬Έμ œκ°€ λ˜μ§€ μ•Šμ§€λ§Œ, μ»΄ν¬λ„ŒνŠΈμ˜

λ Œλ”λ§μ΄ 자주 λ°œμƒν•˜κ±°λ‚˜, λ Œλ”λ§ ν•΄μ•Ό ν•  μ»΄ν¬λ„ŒνŠΈμ˜ κ°œμˆ˜κ°€ λ§Žμ•„μ§„λ‹€λ©΄ 이 뢀뢄을

μ΅œμ ν™” ν•΄μ£Όμ‹œλŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

 

Average.js

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

const getAverage = numbers => {
  console.log('평균값 계산쀑..');
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
};

const Average = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState('');

  const onChange = useCallback(e => {
    setNumber(e.target.value);
  }, []);

  const onInsert = useCallback(
    e => {
      const nextList = list.concat(parseInt(number));
      setList(nextList);
      setNumber('');
    },
    [number, list]
  );

  const avg = useMemo(() => getAverage(list), [list]);

  return (
    <div>
      <input value={number} onChange={onChange} />
      <button onClick={onInsert}>등둝</button>
      <ul>
        {list.map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      <div>
        <b>평균 κ°’:</b> {avg}
      </div>
    </div>
  );
};

export default Average;

 

useCallback 의 첫번째 νŒŒλΌλ―Έν„°μ—λŠ” μš°λ¦¬κ°€ 생성해주고 싢은 ν•¨μˆ˜λ₯Ό λ„£μ–΄μ£Όκ³ , λ‘λ²ˆμ§Έ

νŒŒλΌλ―Έν„°μ—λŠ” 배열을 λ„£μ–΄μ£Όλ©΄ λ˜λŠ”λ° 이 λ°°μ—΄μ—λŠ” μ–΄λ–€ 값이 λ°”λ€Œμ—ˆμ„ λ•Œ ν•¨μˆ˜λ₯Ό μƒˆλ‘œ

생성해주어야 ν•˜λŠ”μ§€ λͺ…μ‹œν•΄μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.

 

λ§Œμ•½μ— onChange 처럼 λΉ„μ–΄μžˆλŠ” 배열을 λ„£κ²Œ 되면 μ»΄ν¬λ„ŒνŠΈκ°€ λ Œλ”λ§ 될 λ•Œ 단 ν•œλ²ˆλ§Œ

ν•¨μˆ˜κ°€ μƒμ„±λ˜λ©°, onInsert 처럼 λ°°μ—΄ μ•ˆμ— number 와 list λ₯Ό λ„£κ²Œ 되면 인풋 λ‚΄μš©μ΄

λ°”λ€Œκ±°λ‚˜ μƒˆλ‘œμš΄ ν•­λͺ©μ΄ μΆ”κ°€ 될 λ•Œλ§ˆλ‹€ ν•¨μˆ˜κ°€ μƒμ„±λ©λ‹ˆλ‹€.

 

7. useRef

useRef Hook 은 ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈμ—μ„œ ref λ₯Ό μ‰½κ²Œ μ‚¬μš© ν•  수 있게 ν•΄μ€λ‹ˆλ‹€. Average

μ»΄ν¬λ„ŒνŠΈμ—μ„œ 등둝 λ²„νŠΌμ„ λˆŒλ €μ„ λ•Œ ν¬μ»€μŠ€κ°€ 인풋 μͺ½μœΌλ‘œ λ„˜μ–΄κ°€λ„λ‘ μ½”λ“œλ₯Ό

μž‘μ„±ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

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

const getAverage = numbers => {
  console.log('평균값 계산쀑..');
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
};

const Average = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState('');
  const inputEl = useRef(null);

  const onChange = useCallback(e => {
    setNumber(e.target.value);
  }, []); // μ»΄ν¬λ„ŒνŠΈκ°€ 처음 λ Œλ”λ§ 될 λ•Œλ§Œ ν•¨μˆ˜ 생성
  const onInsert = useCallback(
    e => {
      const nextList = list.concat(parseInt(number));
      setList(nextList);
      setNumber('');
      inputEl.current.focus();
    },
    [number, list]
  ); // number ν˜Ήμ€ list κ°€ λ°”λ€Œμ—ˆμ„ λ•Œλ§Œ ν•¨μˆ˜ 생성

  const avg = useMemo(() => getAverage(list), [list]);

  return (
    <div>
      <input value={number} onChange={onChange} ref={inputEl} />
      <button onClick={onInsert}>등둝</button>
      <ul>
        {list.map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      <div>
        <b>평균 κ°’:</b> {avg}
      </div>
    </div>
  );
};

export default Average;

7.1 둜컬 λ³€μˆ˜ μ‚¬μš©ν•˜κΈ°

μΆ”κ°€μ μœΌλ‘œ, μ»΄ν¬λ„ŒνŠΈ 둜컬 λ³€μˆ˜λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•  λ•Œλ„ useRef λ₯Ό ν™œμš© ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ—¬κΈ°μ„œ

둜컬 λ³€μˆ˜λΌ 함은, λ Œλ”λ§μ΄λž‘μ€ 관계 없이 λ°”λ€” 수 μžˆλŠ” 값을 μ˜λ―Έν•©λ‹ˆλ‹€. λ§Œμ•½μ— 클래슀 

ν˜•νƒœμ˜ μ»΄ν¬λ„ŒνŠΈλ‘œ λ”°μ§€μžλ©΄ λ‹€μŒκ³Ό 같은 μ½”λ“œμž…λ‹ˆλ‹€.

import React, { Component } from 'react';

class MyComponent extends Component {
  id = 1
  setId = (n) => {
    this.id = n;
  }
  printId = () => {
    console.log(this.id);
  }
  render() {
    return (
      <div>
        MyComponent
      </div>
    );
  }
}

export default MyComponent;

 

μ΄λŸ¬ν•œ μ½”λ“œλ₯Ό ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈλ‘œ μž‘μ„±ν•œλ‹€λ©΄ λ‹€μŒκ³Ό 같이 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

import React, { useRef } from 'react';

const RefSample = () => {
  const id = useRef(1);
  const setId = (n) => {
    id.current = n;
  }
  const printId = () => {
    console.log(id.current);
  }
  return (
    <div>
      refsample
    </div>
  );
};

export default RefSample;

8. μ»€μŠ€ν…€ Hooks λ§Œλ“€κΈ°

λ§Œμ•½μ— μ—¬λŸ¬ μ»΄ν¬λ„ŒνŠΈμ—μ„œ λΉ„μŠ·ν•œ κΈ°λŠ₯을 κ³΅μœ ν•˜κ²Œ λ˜λŠ” 일이 λ°œμƒν•œλ‹€λ©΄ 이λ₯Ό μš°λ¦¬λ“€λ§Œμ˜

Hook 을 μž‘μ„±ν•˜μ—¬ λ‘œμ§μ„ μž¬μ‚¬μš© ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

8.1 useInputs

ν•œλ²ˆ μš°λ¦¬κ°€ 기쑴에 Info μ»΄ν¬λ„ŒνŠΈμ—μ„œ μ—¬λŸ¬κ°œμ˜ 인풋을 κ΄€λ¦¬ν•˜κΈ° μœ„ν•˜μ—¬ useReducer 둜 

ν•΄κ²°ν–ˆλ˜ μž‘μ„±ν–ˆλ˜ λ‘œμ§μ„ useInputs λΌλŠ” Hook으둜 λ”°λ‘œ λΆ„λ¦¬ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€

 

src 디렉터리에 useInputs.js νŒŒμΌμ„ λ§Œλ“€κ³  λ‹€μŒ μ½”λ“œλ₯Ό μž‘μ„±ν•΄λ³΄μ„Έμš”

 

useInputsjs

import { useReducer } from 'react';

function reducer(state, action) {
  return {
    ...state,
    [action.name]: action.value,
  };
}

export default function useInputs(initialForm) {
  const [state, dispatch] = useReducer(reducer, initialForm);
  const onChange = e => {
    dispatch(e.target);
  };
  return [state, onChange];
}

 

Info.js

import React from 'react';
import useInputs from './useInputs';

const Info = () => {
  const [state, onChange] = useInputs({
    name: '',
    nickname: '',
  });
  const { name, nickname } = state;
  return (
    <div>
      <div>
        <input name="name" value={name} onChange={onChange} />
        <input name="nickname" value={nickname} onChange={onChange} />
      </div>
      <div>
        <div>
          <b>이름:</b> {name}
        </div>
        <div>
          <b>λ‹‰λ„€μž„: </b>
          {nickname}
        </div>
      </div>
    </div>
  );
};

export default Info;

 

8.2 usePromise

μ΄λ²ˆμ—λŠ” ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈμ—μ„œ Promise λ₯Ό 더 μ‰½κ²Œ μ‚¬μš© ν•  수 μžˆλŠ” Hook 을 λ§Œλ“€μ–΄λ΄…μ‹œλ‹€.

 

src 디렉터리에 usePromise.js νŒŒμΌμ„ μƒμ„±ν•˜κ³  λ‹€μŒ μ½”λ“œλ₯Ό μž…λ ₯ν•΄λ³΄μ„Έμš”

 

usePromise.js

import { useState, useEffect } from 'react';

export default function usePromise(promiseCreator, deps) {
  const [resolved, setResolved] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const process = async () => {
    setLoading(true);
    try {
      const result = await promiseCreator();
      setResolved(result);
    } catch (e) {
      setError(e);
    }
    setLoading(false);
  };

  useEffect(() => {
    process();
  }, deps);

  return [loading, resolved, error];
}

 

μœ„ μ»€μŠ€ν…€ ν›…μ—μ„œλŠ” useState와 useEffect λ₯Ό ν•¨κ»˜ μ‚¬μš©ν•˜μ˜€μŠ΅λ‹ˆλ‹€. 이 ν•¨μˆ˜λŠ” ν”„λ‘œλ―ΈμŠ€λ₯Ό 

μƒμ„±ν•˜λŠ” promiseCreator 와, μ–Έμ œ ν”„λ‘œλ―ΈμŠ€λ₯Ό μƒˆλ‘œ λ§Œλ“€μ§€μ— λŒ€ν•œ 쑰건을 μœ„ν•œ deps

배열을 νŒŒλΌλ―Έν„°λ‘œ λ°›μ•„μ˜΅λ‹ˆλ‹€. 이 deps 배열은 useEffect 의 λ‘λ²ˆμ§Έ νŒŒλΌλ―Έν„°λ‘œ μ „λ‹¬λ˜λ©°,

기본값은 λΉ„μ–΄μžˆλŠ” λ°°μ—΄μž…λ‹ˆλ‹€.

 

UsePromiseSample.js

import React from 'react';
import usePromise from './usePromise';

const wait = () => {
  // 3초 후에 λλ‚˜λŠ” ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜
  return new Promise(resolve =>
    setTimeout(() => resolve('Hello hooks!'), 3000)
  );
};
const UsePromiseSample = () => {
  const [loading, resolved, error] = usePromise(wait, []);

  if (loading) return <div>λ‘œλ”©μ€‘..!</div>;
  if (error) return <div>μ—λŸ¬ λ°œμƒ!</div>;
  if (!resolved) return null;

  return <div>{resolved}</div>;
};

export default UsePromiseSample;

 

App.js

import React from 'react';
import UsePromiseSample from './UsePromiseSample';

const App = () => {
  return <UsePromiseSample />;
};

export default App;

velog.io/@velopert/react-hooks

 

λ¦¬μ•‘νŠΈμ˜ Hooks μ™„λ²½ μ •λ³΅ν•˜κΈ°

React Hooks λŠ” v16.8 에 λ„μž…λœ κ°œλ…μœΌλ‘œμ„œ, ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈμ—μ„œλ„ μƒνƒœ 관리λ₯Ό ν•  수 μžˆλŠ” useState, 그리고 λ Œλ”λ§ 직후 μž‘μ—…μ„ μ„€μ •ν•˜λŠ” useEffect λ“±μ˜ κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. 이에 λŒ€ν•˜μ—¬ ν•œλ²ˆ μžμ„Ένžˆ

velog.io

 

λ°˜μ‘ν˜•