๐Ÿธ Spread operator์™€ ์ปดํฌ๋„ŒํŠธ ํ˜ธ์ถœ ๋ฐฉ์‹

Lee Jooamยท2022๋…„ 6์›” 3์ผ
0

Spread operator

const obj = {id: 'me', age: 20};

console.log(...obj);

์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ๋Š” ์–ด๋–ค ์ถœ๋ ฅ์„ ํ• ๊นŒ?

์‚ฌ์‹ค ์ด ์ฝ”๋“œ๋Š” ํƒ€์ž… ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. obj๋Š” iterableํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. spread operator๋Š” ๋ฐฐ์—ด์ด๋‚˜, ๋ฌธ์ž์—ด ๋“ฑ iterableํ•œ ๊ฐ์ฒด์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

const arr = [1, 2, 3, 4, 5];

console.log({ ...arr });

์ตœ์‹  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์—์„œ๋„ spread operator๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ์œ„์˜ ์˜ˆ์‹œ์—์„œ๋Š” key-value ํ˜•ํƒœ๋กœ index: item์ธ object๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค.

const person = { name: 'lee', age: 20 };
const info = { address: 'incheon' };

const me = { ...person, ...info };

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ๋ฒ•์„ ์ด์šฉํ•˜๋ฉด ์ƒˆ๋กœ์šด obj์— ์†์„ฑ๋“ค์„ ์—ด๊ฑฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

๐Ÿ˜ฅ ์˜๋ฌธ์ 

๋‚ด๊ฐ€ ๊ฐ€์ง„ ์˜๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

const withCheckPermission = (TargetComponent) => {
  return function WithCheckPermission(props) {
    const [permission, setPermisson] = useState(null);

    useEffect(() => {
      async function checkPermisson() {
        const result = await fetch("/api/checkPermisson").then((res) =>
          res.json()
        );

        setPermisson(result);
      }

      checkPermisson();
    }, []);

    return <TargetComponent {...props} permission={permission} />;
  };
};

HOC์— ๋Œ€ํ•œ ์˜ˆ์‹œ๋ฅผ ์ž‘์„ฑํ•˜๋˜ ์ค‘ {...props} ๋ถ€๋ถ„์ด ๋ˆˆ์— ๊ฑฐ์Šฌ๋ ธ๋‹ค. ๋‹น์—ฐํ•˜๊ฒŒ ์‚ฌ์šฉํ–ˆ๋˜ ๊ฒƒ์ธ๋ฐ ์–ด๋–ป๊ฒŒ ์ €๋Ÿฐ ๋ฌธ๋ฒ•์ด ๊ฐ€๋Šฅํ•œ ๊ฑด์ง€ ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค.

JSX์—์„œ ์ค‘๊ด„ํ˜ธ๋Š” ์ผ๋ฐ˜์ ์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•จ์ด๋ผ๊ณ  ๋“ค์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ props๋Š” iterableํ•˜์ง€ ์•Š์€ ๊ฐ์ฒด์ธ๋ฐ ์–ด๋–ป๊ฒŒ spread operator๋ฅผ ์ด์šฉํ•ด ์ „๊ฐœํ• ๊นŒ?

Spread Attributes
If you already have props as an object, and you want to pass it in JSX, you can use ... as a โ€œspreadโ€ syntax to pass the whole props object. These two components are equivalent:

function App1() {
  return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
  const props = {firstName: 'Ben', lastName: 'Hector'};
  return <Greeting {...props} />;
}

You can also pick specific props that your component will consume while passing all other props using the spread syntax.

์ฐธ๊ณ ๋กœ ๊ณต์‹ ๋ฌธ์„œ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‚˜์™€์žˆ๋‹ค.

Component !== Function Call

<Component />
Component();

๋‘˜์˜ ์ฐจ์ด๋Š” ๋ญ˜๊นŒ? ์ผ๋‹จ ํ•จ์ˆ˜ ํ˜ธ์ถœ๊ณผ ์ปดํฌ๋„ŒํŠธ ํ˜ธ์ถœ์€ ๋‹ค๋ฅด๋‹ค. ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ์ง€ ์˜ˆ์‹œ๋ฅผ ์ด์šฉํ•ด ์•Œ์•„๋ณด์ž.

ํ•ด๋‹น ๋‚ด์šฉ์€ React: Calling functional components as functions์„ ์ฝ๊ณ  ์ž‘์„ฑ๋˜์—ˆ๋‹ค.

const Counter = ({ onClick }) => {
  const [count, setCount] = useState(0);
  const incrementTotal = () => {
    setTotal((prev) => prev + 1);
  };
  
  const increment = () => {
    setCount((prev) => prev + 1);
    onClick();
  };

  return (
    <div className='Counter'>
      <div>{count}</div>
      <button onClick={increment}>+</button>
    </div>
  );
};

const ComponentTest = () => {
  const [total, setTotal] = useState(0);

  return (
    <div>
      <div>The Total is {total}</div>
      <Counter onClick={incrementTotal} />
      <Counter onClick={incrementTotal} />
      <Counter onClick={incrementTotal} />
    </div>
  );
};

๊ฐ๊ฐ์˜ ์นด์šดํ„ฐ๋งˆ๋‹ค total๊ณผ ์ž์‹ ์˜ count๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๊ณ  ์žˆ๋‹ค. ๋ณ„ ๋ฌธ์ œ ์—†์ด ์ž‘๋™๋œ๋‹ค. ํ•˜์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์š”์†Œ๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค๋ฉด ์–ด๋–จ๊นŒ?

const ComponentTest = () => {
  const [total, setTotal] = useState(0);
  const incrementTotal = () => {
    setTotal((prev) => prev + 1);
  };
  
  const CounterInComponent = ({ onClick }) => {
    const [count, setCount] = useState(0);
    const increment = () => {
      setCount((prev) => prev + 1);
      onClick();
    };

    return (
      <div className='Counter'>
        <div>{count}</div>
        <button onClick={increment}>+</button>
      </div>
    );
  };

  return (
    <div>
      <div>The Total is {total}</div>
		...
      <CounterInComponent onClick={incrementTotal} />
    </div>
  );
};

์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ ์นด์šดํ„ฐ๋ฅผ ์ƒ์„ฑํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•˜๋ฉด ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

total์€ ์ฆ๊ฐ€ํ•˜์ง€๋งŒ CounterInComponent์˜ count๋Š” ์ฆ๊ฐ€ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด ํ˜„์ƒ์˜ ์›์ธ์€ ๊ทธ๋ž˜๋„ ๋ช…๋ฐฑํ•˜๋‹ค.

total์ด ์ฆ๊ฐ€ํ•˜๋ฉด ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•˜๊ณ  CounterInComponent ๋˜ํ•œ ์žฌ์„ ์–ธ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋•Œ ์žฌ์„ ์–ธ๋œ CounterInComponent์™€ ๊ธฐ์กด์˜ CounterInComponent๋Š” ๋‹ค๋ฅธ ์ฐธ์กฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ดˆ๊ธฐํ™”๋˜๋Š” ๊ฒƒ์ด๋‹ค.

{CounterInComponent({ onClick: incrementTotal })}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ผ๋ฐ˜์ ์ธ ํ•จ์ˆ˜ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด์ž. ๋ฌธ์ œ๊ฐ€ ์‚ฌ๋ผ์กŒ๋‹ค...

๊ทธ๋ฆฌ๊ณ  React devtools๋ฅผ ํ™•์ธํ•˜๋ฉด ์‹ ๊ธฐํ•œ ํ˜„์ƒ์ด ๋ฒŒ์–ด์ง„๋‹ค.

์œ„๋Š” ์ปดํฌ๋„ŒํŠธ ํ˜•ํƒœ๋กœ ํ˜ธ์ถœํ•œ ๊ฒฐ๊ณผ, ์•„๋ž˜๋Š” ์ผ๋ฐ˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ๋ถˆ๋Ÿฌ์˜จ ๊ฒฐ๊ณผ์ด๋‹ค.

์ผ๋ฐ˜ ํ•จ์ˆ˜ํ˜ธ์ถœ์€ ๋ฆฌ์•กํŠธ๊ฐ€ ์ปดํฌ๋„ŒํŠธ๋กœ ์ธ์‹ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด๊ฒƒ์ด ๋œปํ•˜๋Š” ๊ฑด ๋ฆฌ์•กํŠธ๊ฐ€ ํ•ด๋‹น ์š”์†Œ์˜ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค!

๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ ๋ฆฌ๋ Œ๋”๋ง์œผ๋กœ CounterInComponent๋„ ๋‹ค์‹œ ์„ ์–ธ๋์ง€๋งŒ ๋ฆฌ์•กํŠธ๋Š” ๊ทธ๊ฒƒ์ด ์ƒˆ๋กœ์šด ์ฐธ์กฐ์ด๋“  ๋ง๋“  ๊ด€์—ฌํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ทธ๋ƒฅ ์ผ๋ฐ˜์ ์ธ TextNode์ฒ˜๋Ÿผ ์ผ๋ฐ˜ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์ทจ๊ธ‰ํ•ด๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ด๋‹ค.

๋‹ค์‹œ ๋Œ์•„์™€์„œ??

์•„๋ฌดํŠผ ๋‚ด๊ฐ€ ์ด๋Ÿฐ ํฌ์ŠคํŠธ๋ฅผ ์ฐพ์•„ ๋ณธ ์ด์œ ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ผ๋ฐ˜์ ์ธ function call์ด๊ณ  {...props}์˜ ์ „๊ฐœ ์—ฐ์‚ฐ์ž๊ฐ€ rest operator ํ˜•ํƒœ๋กœ ์ „๋‹ฌ๋˜๋‚˜ ์˜๋ฌธ์ด ๋“ค์–ด์„œ์ด๋‹ค.

babel์ด ์ผ๋ฐ˜์ ์ธ function call ๋ณ€ํ™˜ํ•ด์ค€๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์œ ์‚ฌํ•˜๊ธด ํ•˜์ง€๋งŒ ์ผ๋‹จ ๊ฒฐ๋ก ์€ ์•„๋‹ˆ๋‹ค๋Š” ์ชฝ์œผ๋กœ ๊ธฐ์šธ์—ˆ๋‹ค.

๐Ÿ˜ ๊ฒฐ๋ก 

<Component {...props1} {...props2} />

์ƒ๊ฐํ•ด๋ณด๋‹ˆ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‚ฌ์šฉ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ „๊ฐœ ์—ฐ์‚ฐ์ž๋ฅผ ๋‘ ๋ฒˆ ์‚ฌ์šฉํ•ด ์ „๋‹ฌํ•ด๋„ ๋ฌธ๋ฒ•์ ์ธ ์˜ค๋ฅ˜๋Š” ์—†๋‹ค.

rest operator๋Š” ์•„๋‹Œ ๊ฒƒ ๊ฐ™๋‹ค.

const obj1 = { name: "lee" };

<Component {...obj1} name='kim' />

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‹คํ—˜์„ ํ•˜๋‹ค ์‹ค๋งˆ๋ฆฌ๊ฐ€ ์žกํ˜”๋‹ค. ์œ„์˜ ์ฝ”๋“œ์—์„œ name props์˜ ๊ฒฐ๊ณผ๋Š” kim์ด๋‹ค. ๋’ค์— ์žˆ๋Š” ๋…€์„์ด ์ ์šฉ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  props๋Š” ๊ฐ์ฒด์ด๋‹ค.

const person = { name: 'lee', age: 20 };
const info = { address: 'incheon' };

const me = { ...person, ...info };

์œ„์˜ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด ์˜ˆ์‹œ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒˆ๋กœ์šด ๊ฐ์ฒด์— ์†์„ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

props๋„ ๋น„์Šทํ•œ ํ˜•ํƒœ๋กœ ์ž‘๋™ํ•˜๋Š” ๊ฒŒ ์•„๋‹๊นŒ?

๊ธฐ์กด props ๊ฐ์ฒด์— {...obj}๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ํ˜•์‹์œผ๋กœ ํ•œ๋‹ค๋ฉด key=value๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฒฐ๊ณผ์ ์œผ๋กœ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋™์ž‘ํ•œ๋‹ค.

๋Œ๊ณ  ๋Œ์•„ ๋‚ด๋ฆฐ ๊ฒฐ๋ก ์ด์ง€๋งŒ ํƒ€๋‹นํ•œ ๊ฒฐ๋ก ์ธ ๊ฒƒ ๊ฐ™๋‹ค!

Babel playground์— ์ •๋‹ต์ด ๋‚˜์™€์žˆ์—ˆ๋„ค์š” ใ…Žใ…Ž

profile
ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋กœ ๊ฑธ์–ด๊ฐ€๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€