[React] Changing complex states & ES6 Spread Operator

Minju Kim·2022년 3월 13일
0

React

목록 보기
7/15
post-thumbnail
post-custom-banner

Changing Complex states

form을 통해서 여러가지 값 상태들을 바꾸는 것을 알아보자!

useState를 한 개 쓰는 것은 이제 알았다. useState를 통해서 prop 하나를 바꾸는 방법은 알게 되었는데, 그렇다면 여러개를 한번에 바꿀수는 없을까? 여러개를 한꺼번에 바꾸지 못하면 바꾸고 싶은 값을 다 일일이 useState를 통해 선언해줘야 하는데, 너무 비효율적이지 않은가!! 심지어 한 개의 form안에서 작동하는 매우 접근성이 강한 애들인데 말이다.

👉 이럴 때 해결방법은, 객체를 이용하는 것이다.
아 뭐, 너무 간단하네! 라고 생각한 나에게 주어진 것은..

🤯 콘솔창을 가득 채우는 빨간 줄 여러개.. 그런데 이제 Never Ending...

  1. useState 초기값에 객체를 넣어주는 것인데 자꾸 “=”를 썼다. (생각하면서 작성해 이친구야..)
  2. 조건문 작성시에 name하고 비교하는데 문자열이라 당연히 “”로 감싸줘야 하는데 그냥 fName하고 비교하고 왜 안되는지 머리를 싸맸더랬지..
  3. return문 안을 {}로 묶어주지 않았다. 이건 내가 정확히 무엇을 반환하고 있는지 생각 안했기 때문.
  4. return문 안에서 값을 돌려줄때, 나는 결국 객체를 반환하는 것이기 때문에 dot notation을 통해 객체가 각 property별 반환해야 하는 값 하나하나를 작성해 줘야 하는데 그냥 냅다 value를 작성하며..

🤔 이정도면 뭐, 무슨일이 일어나고 있는거 거의 통째로 이해 못했다고 할 수 있다. ^ ^

그래 아무것도 아니야. 에러는 배울 수 있는 좋은 기회일 뿐....ㅎ.ㅎ 다시 마음을 다잡고 하나하나 차근차근 이해하며 살펴보았다.

🧤 step별 해결방법

1. state초기값을 단일 값이 아닌 객체로 설정해준다.

```jsx
 const [contact, setContact] = useState({
    fName: "",
    lName: "",
    email: ""
  });
```

2. 해당 state를 변경되어야 하는 위치에 넣어준다. 어떤형태로? 객체형태로!!

🛑 여기서 기억할 점 하나! return문 안에 있기 때문에 우리는 jsx문법을 사용중이다.

jsx문법에서 javascript를 사용하려면 {} curly bracket 안에 값을 넣어주어야 하며, 우리는 객체의 각각 key에 해당하는 value를 가져올 것이기 때문에 “.” dot notation을 통해 가져오고 있으며, jsx 문법이기에 띄어쓰기가 그대로 적용된다.

```jsx
<h1>
  Hello {contact.fName} {contact.lName}
</h1>
```

3. 각각 input에 동일한 event 함수를 달아주고, 함수를 정의해준다.

```jsx
function handleChange();

<input onChange={handleChange} name="fName" placeholder="First Name" value={contact.fName}/>
<input onChange={handleChange} name="lName" placeholder="Last Name" value={contact.lName}/>
<input onChange={handleChange} name="email" placeholder="Email" value={contact.email}/>
```

4. setState에 대한 함수를 정의해준다!

  1. 🛑 주의 1. destructuring 문법을 이용해준다.

    const name = [event.target](http://event.target).name; const value = event.target.value 를 살펴보면, event.target 객체의 property를 사용하고 있는 것을 알 수 있다. 객체를 destructuring 문법으로 작성하려면 {}안에서 분해하면된다.

    🛑 주의 2. 여러 값들을 반환하려면 object나 array형태로 만들어 반환해야 한다는 것을 기억!

    setContact에는 함수가 들어있고 그 함수는 조건에 따라서 세 가지 값을 바꿔야 하는 상황이다. 우리는 이걸 위해 이미 사전에 contact를 객체로 만들어주었고, 객체를 반환하는 것이기 때문에 모든 값들을 {}안에 묶어서 반환하고 있다. return {} 🤯 순간 return문인데 왜 {}로 묶나 헷갈렸었다. 정신차려 이친구야...

    Returning Multiple Values from a Function

    🛑 주의 3. prevValue로 이전 값을 잡아놔야한다!! 그리고prevValue는 이전 state, 객체! 그러니까 값을 하나하나 사용하고 싶다면 . notation 사용!

    지금 하나의 state를 객체 형태로 움직이고 있는 것이다. 따라서 새로운 event가 일어날 때마다 rendering이 다시되고 있다는 것을 떠올려보면 된다. 실제로 개발자 도구를 열어서 보면, 우리가 값 하나하나 입력할 때마다 이전 state는 사라지고 새롭게 rendering이 되면서 초기값 → 우리가 입력한 값으로 변경되는 것을 확인할 수 있다. 즉, 이전에 내가 fName에다가 뭐라고 썼든간에, lName에다가 새로 입력하면 다시 fName은 초기 상태인 “”로 입력이 되면서 화면에서 값이 사라지는 것을 볼 수 있다.

    Hooks API Reference - React

    function handleChange(event){
       const {name, value} = event.target; 
        
       setContact(prevValue => {
          if(name === "fName"){
            return {
            fName : value,
            lName : prevValue.lName,
            email : prevValue.email,
            }
          }else if(name === "lName"){
            return {
            fName : prevValue.fName,
            lName : value,
            email : prevValue.email,
            }
          }else if(name === "email"){
            return {
            fName : prevValue.fName,
            lName : prevValue.lName,
            email : value,
            }
          }
        })

5. 마지막! ‘value’값이 state와 바인딩 될 수 있도록 value값을 묶어준다.

```jsx
value={contact.fName}
value={contact.lName}
value={contact.email}
```

전체 코드

import React, { useState } from "react";

function App() {
  const [contact, setContact] = useState({
    fName: "",
    lName: "",
    email: ""
  });

  function handleChange(event){
   const {name, value} = event.target; 
    
   setContact(prevValue => {
      if(name === "fName"){
        return {
        fName : value,
        lName : prevValue.lName,
        email : prevValue.email,
        }
      }else if(name === "lName"){
        return {
        fName : prevValue.fName,
        lName : value,
        email : prevValue.email,
        }
      }else if(name === "email"){
        return {
        fName : prevValue.fName,
        lName : prevValue.lName,
        email : value,
        }
      }
    })
  }

  return (
    <div className="container">
      <h1>
        Hello {contact.fName} {contact.lName}
      </h1>
      <p>{contact.email}</p>
      <form>
        <input onChange={handleChange} name="fName" placeholder="First Name" value={contact.fName}/>
        <input onChange={handleChange} name="lName" placeholder="Last Name" value={contact.lName}/>
        <input onChange={handleChange} name="email" placeholder="Email" value={contact.email}/>
        <button>Submit</button>
      </form>
    </div>
  );
}

export default App;

구현 결과


⭐️ 그런데 의문이 든다..중간에 return 값을 계속 반복해서 똑같은거를 작성하고 있는데, 더 간단한 방법 없을까? 분명히 있을 것 같다 분명히 만들었을 것 같은 느낌적인 느낌이 매우 강하게 치솟는다!!

ES6 Spread Operator 문법

스프레드 연산자는 배열, 함수 parmeter, 객체에서 사용할 수 있다.

1) 배열을 병합, 복사할 수 있다.
2) 함수의 rest parameter로 사용하거나, 호출 인자로 사용할 수 있다.
3) 객체 복사 또는 업데이트에 사용할 수 있다.

✅ Spread Operator & 배열

배열 병합

const citrus = ["Lime", "Lemon", "Orange"];
const fruits = ["Apple", "Banana", "Coconut", ...citrus]

console.log(fruits);
// ["Apple", "Banana", "Coconut", "Lime", "Lemon", "Orange"]

배열 복사

// 😃 Without Spread Operator, the original array CAN BE CHANGED
const arr1 = ['민주', '민주2'];
const arr2 = arr1;
arr2.push = '민주3'

console.log(arr1);
// ['민주', '민주2', '민주3'];

// 😃 With Spread Operator, the original array CAN NOT be CHANGED - 얕은복사수행!
const arr1 = ['민주', '민주2'];
const arr2 = [...arr1];
arr2.push = '민주3'

console.log(arr1); // ['민주', '민주2'] 원본 배열은 변경되지 않는다.
console.log(arr2); // ['민주', '민주2', '민주3'];

✅ Spread Operator & 함수

Rest Parameter로 사용 (함수 정의시)

파라미터로 오는 애들을 잡아서 ‘배열'에 집어넣는다.

function add(...rest){
	let sum = 0;
	for(let item of rest){
		sum += item;
	}
	return sum
}

console.log(add(1)); // 1
console.log(add(2,3); // 5
console.log(add(2,3,4,5); // 14

함수 호출 인자로 사용 (함수 호출시) - 그러니까 그 배열을 통째로 다 가져오는 거다

const numbers = [1,4,2,5];
Math.min(...numbers);

✅ Spread Operator & 함수

객체 복사

const myName = { fName: "민주", lName: "김" };
myName = {...myName, gender:"female"};

console.log(myName); // {fName: "민주", lName: "김", gemder: "female"}

객체 업데이트 - 프로퍼티 오버라이드하기!

const myName = { fName: "민주", lName: "김" };
myName = {...myName, fName: "영희", gender:"female"};

console.log(myName); //fName: "영희", lName: "김", gender:"female"

Complex States + Spread Operator

아까 그 예시로 돌아와서! Spread 연산자를 이용해서 코드를 줄여보자!

function handleChange(event){
   const {name, value} = event.target; 
    
    setContact(prevValue => {
      return {
        ...prevValue,
        [name]: value
      }  
    })
  }

🛑 주의할 점! 나는 정의해 놓은 name을 가져와서 key로 사용하고 싶기 때문에 이럴 경우 [ ] bracket notation을 사용해서 작성해 주어야 한다. 만약 그냥 name이라고 작성하면 키의 값이 name인, 일반적인 key:value를 작성하는 구문이 되어 버린다.

😃💡느낀점

자바스크립트 기본 문법이 매!!우!! 중요하다.
코드가 어떻게 돌아가는지 자!!세!!히!! 살펴보고 정!!확!!히!! 이해하자.

[ES6] Spread Operator (스프레드 연산자)
Angela Webdev

profile
⚓ A smooth sea never made a skillful mariner
post-custom-banner

0개의 댓글