props와 useState

seul_velog·2022년 4월 1일
0

React

목록 보기
3/11
post-thumbnail
post-custom-banner

1. props(properties)

  • 어떠한 값을 컴포넌트에게 전달해줘야 할 때 사용한다.
  • 컴포넌트 안에서 자체적으로 데이터를 정의해서 사용하는 state와는 다르게, props은 컴포넌트 외부에서 데이터를 제공받는다.
    → 이는 컴포넌트 재사용을 높이기 위함이다.
  • 상황에 따라 주어진 데이터를 받아서 그 데이터에 맞게 UI를 보여주기 위해서 사용된다.



1-1. props 사용해보기

✍️ Hello컴포넌트에 name 값을 전달해주고, Hello컴포넌트에서 name 값을 사용해보자.

// App.js
import React from 'react';
import Hello from './Hello';
import './App.css';

function App() {
  return <Hello name='seul' />;
}

export default App;
// Hello.js
import React from 'react';

function Hello(props) { // 파라미터로 props를 받아오자.
  return <div>안녕하세요 ! {props.name}</div>;
}

export default Hello;
  • 컴포넌트에게 전달되는 props는 파라미터를 통해서 조회할 수 있다. 이때 props는 객체 형태로 전달된다. 콘솔에 찍어보자.🤔
  • props.name 을 통해서 name의 값을 조회할 수 있다.

📌 구조 분해 (비구조화 할당) 문법

  • 구조분해 문법을 사용해서 코드를 간단하게 사용할 수 있다.
function Hello({ color, name }) {
  return <div style={{ color }}>안녕하세요 ! {name}</div>;
}
  • ❓ return 에서 중괄호가 이중으로 들어가는 것과 파라미터로 비구조화 할당이 이루어지는 것처럼 보이는 부분이 궁금했다.

    • ❗️ style= 안에 중괄호가 두번 들어가는 이유는 가장 위 {}는 jsx문법이고, 내부 {}은 객체리터럴이기 때문이라고 한다.
    • ❗️ 함수의 파라미터에서도 비구조화 할당을 할 수 있다!
      +) 만약 1행에서 b의 값의 주어지지 않으면 console.log(b)는 undefiend가 출력된다.
    const object = { a: 1, b: 2 };
    
    function print({ a, b }) {
      console.log(a); // 1
      console.log(b); // 2
    }
    
    print(object);



1-2. props 기본값 설정하기

  • 컴포넌트에 props를 지정하지 않았을 때, 기본적으로 사용할 값은 defaultProps 를 이용할 수 있다.
function App() {
  return (
    <>
      <Hello name='seul' color='blue' />
      <Hello color='skyblue' />
    </>
  );
}
function Hello({ color, name }) {
  return <div style={{ color }}>안녕하세요 ! :) {name}</div>;
}

Hello.defaultProps = {
  name: 'default로 설정된 이름입니다.',
};

📌 Props의 기본값은 “True”

  • Prop에 어떤 값도 넘기지 않을 경우, 기본값은 true이다. 아래의 두 JSX 표현은 동일한 표현이다. (일반적으로 prop에 대한 값을 전달하도록 권장한다.)

    <MyTextBox autocomplete />
    
    <MyTextBox autocomplete={true} />



1-3. props.children

  • JSX 표현에서 두 태그 사이의 내용은 props.children 이라는 특수한 prop으로 넘겨진다.
  • 컴포넌트 태그 사이에 넣은 값을 조회하고 싶을 땐, props.children 을 조회한다.
// App.js
function App() {
  return (
    <Wrapper>
      <Hello name='seul' color='blue' />
      <Hello color='skyblue' />
    </Wrapper>
  );
}
// Wrapper.js
function Wrapper({ children }) { // 받아와서
  const style = {
    border: '3px solid pink',
    padding: '16px',
  };
  // props.children을 렌더링 해줘야 한다.
  return <div style={style}>{children}</div>;
}




2. useState

❓ state는 언제 사용할까? 🤔
변동시 자동으로 html에 반영되도록 만들고 싶을 때 사용한다.

  • 컴포넌트에서 동적인 값을 상태(state) 라고 부른다. state는 컴포넌트 UI를 위한 데이터를 보관하는 오브젝트이다.
  • 리액트 16.8에서 Hooks 라는 기능이 도입되면서 함수형 컴포넌트에서도 상태를 관리할 수 있게 되었다.
    리액트 훅에서 state를 쓰기위해 useState라는 API를 이용한다.

    📌 Hook
    기존의 함수형 컴포넌트에서 state와 라이프사이클 메소드를 잘 이용할 수 있게 만들어진 것



2-1. useState 사용하기

✍️ 사용법 3단계

1) import {useState}

2) useState(보관할 자료)

3) let[작명, 작명]


useState() 함수를 호출하면 배열을 반환한다.

  • 1 번째 원소는 현재 상태 값 변수
  • 2 번째 원소는 상태 값을 갱신해주는 Setter 함수
  • useState 괄호 안의 값은 상태의 초기 값
import React, { useState } from 'react'; // 1)

function Counter() {
  const [number, setNumber] = useState(0); // 2)

  const onIncrease = () => {
    setNumber(number + 1); // 3)
  };
  const onDecrease = () => {
    setNumber(number - 1); // 3)
  };

  return (
    <div>
      <h1>{number}</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
    </div>
  );
}

export default Counter;
  • 1) 리액트 패키지에서 useState 라는 함수를 불러와 준다.
  • 2) useState 를 사용할 때 기본값을 파라미터로 넣어서 호출한다. 함수를 호출하면 배열이 반환되며, 첫 번째 원소는 현재 상태, 두 번째 원소는 Setter함수 이다.
    → Setter 함수는 파라미터로 전달 받은 값을 최신 상태로 설정한다.
    → 배열 비구조화 할당(구조분해)문법을 통해서 위 코드처럼 만들 수 있으며, 기존 코드를 통하면 아래와 같이 사용할 수 있다.
    const numberState = useState(0);
    const number = numberState[0];
    const setNumber = numberState[1];

    📌 여기서 setNumber 가 하는 역할
    (1) number의 값을 변경하는 것 + (2)이 함수를 다시 실행하는 것

  • 3) Setter 함수를 사용 할 때, 업데이트를 하고 싶은 새로운 값을 파라미터로 넣어주는 코드이다.
    기존 값을 어떻게 업데이트 할 지에 대한 함수를 등록하는 방식으로도 값을 업데이트 할 수 있다.▼
    const onIncrease = () => {
        setNumber((prevNumber) => prevNumber + 1);
      };
      const onDecrease = () => {
        setNumber((prevNumber) => prevNumber - 1);
      };
    ❓ 3)의 두 가지 방식의 차이가 궁금해서 공식 사이트를 찾아보았다.🤔 ▼



2-2. setState()

  • setState()는 컴포넌트 state의 변경 사항을 대기열에 집어넣고, React에게 해당 컴포넌트와 그 자식들이 갱신된 state를 사용하여 다시 렌더링되어야 한다고 알린다. 이벤트 핸들러와 서버 응답 등에 따라서 UI를 갱신할 때 많이 사용한다.

  • setState() 는 컴포넌트 갱신에 있어서 즉각적인 명령이 아닌 요청이다. 따라서 React는 이 메서드의 실행을 지연시키고 여러 컴포넌트를 한번에 갱신할 수도 있다.

  • 때문에 React는 state 변화가 즉시 적용되는 것을 보장하지 않는다. 즉 setState()는 컴포넌트를 항상 즉각적으로 갱신하지는 않는다.

  • ❓그렇다면 의도치 않은 결과가 나올 수 있다는 말 같은데..
    ✍️ 그 대신에 componentDidUpdate 또는 setState의 콜백(setState(updater, callback))을 사용할 수 있다고 한다. 둘 다 갱신이 적용된 뒤에 실행되는 것이 보장된다고 한다. useState()도 같은 맥락으로 이해했다!
    📌 참고한 페이지
    React.Component_ setState()
    setState()

✍️ 정리하자면..
setState 함수는 두 가지가 있다.
1. setState(newState)
2. setState(prevState => { return newState; })

  • 컴포넌트 내의 state 값에 의존해서 계산할 때, 값을 setState(updated)
    로 설정하기 보다는, setState(prevState => newState)와 같이 state 값을 받아서 업데이트 되는 state값을 만드는 arrow 함수를 호출하는 게 좋다고 한다.😀



2-3. 클래스와 함수의 State

📌 Class

  • 한번 만들어지면 클래스 내의 멤버변수들은 클래스가 만들어질 때 딱 한번만 만들어진다.
  • state가 변경 되거나, props업데이트시 render함수만 계속 반복해서 호출된다.

📌 Function

  • 컴포넌트가 변경되면 코드블럭{} 전체가 계속 반복 호출된다.
  • function 컴포넌트는 props나 state가 변경이 되면 전체가 반복되므로 지역변수 등도 계속해서 반복되게 된다.
  • useState를 사용하면 react가 알아서 자동으로 기억한다. 따라서 반복해서 코드 블록이 실행되어져도 동일한 값을 메모리에 저장해두기 때문에 초기화 걱정없이 사용할 수 있다.
  • useRef와 useCallback도 마찬가지로 메모리에 저장해두고 사용할 수 있다고 한다. 🤔




3. input 상태 관리하기

3-1. useState와 input

function InputSample() {
  const [text, setText] = useState(''); // 1)
  const onChange = (e) => { // 3)
    setText(e.target.value); // 4)
  };
  const onReset = () => {
    setText('');
  };

  return (
    <div>
      <input onChange={onChange} value={text} /> // 2)
      <button onClick={onReset}>초기화</button>
      <div>
        <b>: {text}</b>
      </div>
    </div>
  );
}
  • 1) useState()를 통해서 현재 상태(첫 번째 원소)와 Setter함수(두 번째 원소)를 사용한다.
  • 2) value 값으로 text 상태 값을 준다.
  • 2,3) input에서 onChange 라는 이벤트를 사용, 이 객체의 e.target 은 이벤트가 발생한 DOM인 inputDOM을 가리키게 된다.
  • 4) e.target.value 를 통해서 input에 들어온 value 값을 알 수 있다.
  • 콘솔로 ee.target 을 확인해보자.▼



3-2. 여러개의 input 상태 관리하기

input이 여러개일 경우 또 다른 이벤트 핸들러 함수를 만드는 것 보다 input 태그의 name 속성을 이용하는 방법이 있다.

function InputSample() {
  const [inputs, setInputs] = useState({
    name: '',
    age: '',
  });

  const { name, age } = inputs; // 비구조화 할당을 통해 값을 추출한다.

  const onChange = (e) => {
    const { value, name } = e.target; // 2) e.target에서 name과 value를 추출한다.
    setInputs({
      ...inputs, // 기존의 input 객체를 복사한다.
      [name]: value, // 📌
    });
  };

  const onReset = () => {
    setInputs({
      name: '',
      age: '',
    });
  };

  return (
    <div>
    // 1)
      <input name='name' placeholder='이름' onChange={onChange} value={name} />
      <input name='age' placeholder='나이' onChange={onChange} value={age} />
      <button onClick={onReset}>초기화</button>
      <div>
        <b>: </b>
        {name} ({age})
      </div>
    </div>
  );
}

  • 1) return 안쪽의 각 inputname 값을 부여해서 각 input 을 구분할 수 있게 되었다.

  • 2) 이 값은 e.target.name 을 통해서 조회할 수 있다.

  • 📌 ) 이 부분이 이해가 잘 되지 않아서 여러 자료를 찾아보았다. 🧐
    코드의 의미는 이렇다. → name키를 가진 값을 value로 설정한다.
    이 코드는 [e.target.name]: e.target.value 와 동일하다.
    key 부분에 [] 괄호가 사용된 것을 알아보자! ▼



3-3. Computed property names

계산된 프로퍼티(속성)명
프로퍼티의 이름을 정의하는 새로운 방법

  • {[expression]: value}

  • 객체 리터럴의 프로퍼티명 자리에 대괄호[]와 표현식의 조합으로 사용한다. expression의 실행 결과가 프로퍼티의 이름이 된다.

  • 프로퍼티명을 그대로 사용하는 경우 ▼

    const obj = {name:'hi', age:15}
    
    const newObj = {...obj, name: 'seul'}
    console.log(newObj) // {name: 'seul', age: 15}
  • 표현식을 프로퍼티 명으로 활용하려는 경우 ▼

    const obj = {name:'hi', age:15}
    
    const props = 'name';
    const newObj = {...obj, [props]: 'seul'}
    console.log(newObj) // {name: 'seul', age: 15}

✍️ 예시)

// ex.1)
let name = 'seul';
let obj = {
  [name]: 123
};
obj; // Object { seul: 123 }


// ex.2)
let i = 0
let a = {
  ['foo' + ++i]: i,
  ['foo' + ++i]: i,
  ['foo' + ++i]: i
}

console.log(a.foo1) // 1
console.log(a.foo2) // 2
console.log(a.foo3) // 3


// ex.3)
const items = ["A","B","C"];
const obj = {
[items]: "Hello"
}
console.log(obj); // A,B,C: "Hello"
console.log(obj["A,B,C"]) // "Hello"

✍️ 예시를 보면 전부 객체의 [key] 가 계산되어진 프로퍼티명으로 사용된 것을 알 수 있다.

❗️ 즉, 궁금했던 예제에서의 경우 ▼

  const onChange = (e) => {
    const { value, name } = e.target;
    setInputs({...inputs, [name]: value,});
  };

첫번째 input 에 변경이 발생하면 [name] 에 name 이 들어간다.
두번째 input 에 변경이 발생하면 [name] 에 age 가 들어간다.
그래서 만약 [] 없이 name 으로만 적게되면 age에 대한 값은 업데이트 되지 않을 것이다.

😀 기본적인 문법이 헷갈리면 쉬운 구간에서도 막힐 수 있으니 그때 그때 잘 숙지해두자!





reference)
React-JSX
React-setState()
setState()
vlpt-props,useState
dreamcoding
MDN-Computed property names
JS_Computed property names

profile
기억보단 기록을 ✨
post-custom-banner

0개의 댓글