본문 바로가기
React/기초

리액트[기초] state

by 뿌비 2022. 5. 27.
728x90

state 란?

  • 컴포넌트 내부에서 바뀔 수 있는 값을 의미한다 
  • 클래스형 컴포넌트가 지니고 있는 state함수 컴포넌트에서 useState라는 함수를 통해 사용하는 state가 있다 
  • 컴포넌트 자체적으로 지닌 값으로 컴포넌트 내부에서 값을 업데이트할 수 있다 

클래스형 컴포넌트 state ( state 초기값 설정 방법 1)

  • 컴포넌트에 state의 초기값을 설정할 때는 constructor 메서드(컴포넌트 생성자 메서드)를 작성하여 설정한다
  • 클래스형 컴포넌트에서 constructor를 작성할 때는 반드시 super(props)를 호출해주어야 한다. (이 함수가 호출되면 현재 클래스형 컴포넌트가 상속받고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출해준다)
  • 컴포넌트의 state는 객체 형식 이어야 한다.
// 자식 컴포넌트 
import {Component} from 'react';

class Counter extends Component {

// state 초기값 설정 하기 위해 constructor 메소드 작성
constructor(props){
    super(props); 
    this.state = { // this.state 의 값에 초기값을 설정 해주었다 
    	number : 0 // 초기값 설정
    };
   }
   
   render() {
	const { number } = this.state; // state 를 조회 할때는 this.state로 조회 한다
    return (
    	<div>
        <h1>{number}</h1>
        <button
        	/* 
        	 onclick 을 통해 버튼이 클릭되었을때 호출할 함수를 지정.
             	이벤트로 설정할 함수를 넣어줄때는 화살표 함수 문법을 사용해서 넣어주어야한다
        	*/
            onClick={() => { 
         	// this.setState 를 사용해서 state에 새로운 값을 넣을 수 있다
        	this.setState({ number: number + 1 });
        }}
        >
        +1
        </button>
        </div>
    );
 }
}
export default Counter;

// 부모 컴포넌트
import Counter from './Counter';

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

state ( state 초기값 설정 방법 2)

  • constructor 메서드를 선언하지 않고도  state를 사용해서 state 초기값을 설정할 수 있다
// 자식 컴포넌트 
import {Component} from 'react';

class Counter extends Component {

// constructor 메소드를 선언 하지 않고도 state 를 사용해서 state의 초기값을 설정할 수 있다
 state = {
    // 초기값 설정
    	number : 0, 
        fixedNumber: 0
   };
   
   render() {
	const { number,fixedNumber} = this.state; // state 를 조회 할때는 this.state로 조회 한다
    return (
      //  생략...
    );
 }
}
export default Counter;

state 객체 안에 여러 값이 있을 때 

  • state 객체 안에 여러 값이 있어도 인자로 전달되는 객체 내부에 전달되지 않으면 값이 바뀌지 않는다
  • this.setState 함수인자로 전달된 객체 안에 들어 있는 값만 바꾸어준다 
// 자식 컴포넌트 
import {Component} from 'react';

class Counter extends Component {

// state 초기값 설정 하기 위해 constructor 메소드 작성
constructor(props){
    super(props); 
    this.state = { 
    	// 초기값 설정
    	number : 0,
        fixedNumber: 0
    };
   }
   
   render() {
	const { number ,fixedNumber } = this.state; // state 를 조회 할때는 this.state로 조회 한다
    return (
    	<div>
        <h1>{number}</h1>
        <h2>{fixedNumber}</h2>
        <button
            onClick={() => { 
         	// this.setState 함수는 인자로 전달된 객체 안에 들어 있는값만 바꾸어준다 
        	this.setState({ number: number + 1 });
        }}
        >
        +1
        </button>
        </div>
    );
 }
}
export default Counter;

this.setState

  • this.setState를 사용하면  state에 새로운 값을 넣을 수 있다
  • this.setState를 사용해서 state 값을 업데이트할 때는 상태가 비동기적으로 업데이트된다 
/*
this.setState를 사용해서 state 값을 업데이트 하면 비동기적으로 업데이트 되기 때문에 이렇게 두번 호출 할 경우
분명 2번 사용하는 것이기 때문에 숫자가 2개씩 더해질거라 생각 했는데 버튼을 클릭할때 숫자가 1씩 더해지게 된다
그 이유는, this.setState를 사용한다고 해서 state 값이 바로 바뀌지 않기 때문이다 
이 방법의 해결 책은 this.setState를 사용할때 객체 대신에 함수를 인자로 넣는것 이다.
*/
onClick = {() => {
	this.setState({ number: number + 1 });
    this.setState({ number: this.state.number + 1});
}}

// 함수를 인자로 넣어주는 코드 
onClick = {() => {
   /* 
    prevState 는 기존 상태이고 props는 현재 지니고 있는 props 를 가리킨다 만약 업데이트 하는 과정에서 
    props 가 필요없으면 생략 해도 된다
    */
    this.setState((prevState, props) => {
    return {
     // 업데이트하고 싶은 내용
    }
   });
}}

// 함수를 인자로 넣어주는 코드 props 생략
onClick = {() => {
    this.setState((prevState => {
    return {
     // 업데이트하고 싶은 내용
      number :prevState.number +1
    }
   });
}}

/* 
위 코드랑 완전 똑같지만 이 코드는 함수에서 바로 객체를 반환 한다는 의미의 함수이다 
화살표 함수에서 값을 바로 반환하고 싶을때는 코드 블록 {} 를 생략한다 
그래서 prevState => ({}) 형태의 코드 
*/
onClick = {() => {
    this.setState(prevState => ({
    return {
     // 업데이트하고 싶은 내용
      number :prevState.number +1
   }));
}}

this.setState를 사용해 값을 업데이트한 후 특정 작업을 하고 싶을 때 

  • setState를 사용해 값을 업데이트한 후 특정 작업을 하고 싶을 때는 setState 두 번째 파라미터로 콜백 함수를 등록하면 된다 
onclick = {() => {
this.setState(
    {
    	number: number + 1
    },
    // 두번째 파라미터로 콜백함수 등록 
    () = > {
    	console.log(this.state); // {number:1}
    }
  );
}}

함수 컴포넌트  useState 

  • 리액트 16.8 이후부터는 useState라는 함수를 사용해서 함수 컴포넌트에서도 state를 사용할 수 있게 되었다  (이 과정에서 Hooks을 사용하게 된다)
  • useState 함수의 인자에는 상태의 초기값을 넣어주는데 이때 값의 형태는  state과 다르게 반드시 객체가 아니어도 된다 (숫자, 문자, 객체, 배열.. 다 가능 )
  • 함수를 호출하면 배열이 반환되는데 배열의 첫 번째 원소는 현재 상태이고 두 번째 원소는 상태를 바꾸어주는 함수이다 ( 이를 세터(Setter) 함수라고 한다)
  • 배열 비구조화 할당을 통해 이름은 자유롭게 정할 수 있다 
  • useState는 한 컴포넌트에서 여러 번 사용해도 상관없다
  • 새로운 컴포넌트를 만들 때  클래스형 컴포넌트 state 보다 useState 사용을 더  권장한다 (코드가 더 간결해진다)
// 자식 컴포넌트
import { useState } from 'react';

const Say = () => {
    /*
    배열 비구조화 할당을 통한 message(현재상태), setMessage(상태를 바꾸어주는함수) 이름 설정은 
    자유롭게 해도 된다. 예) text setText 로 해도 상관없음
    */
    const[message, setMessage] = useState('');
    const onClickEnter = () => setMessage('hi');
    const onClickLeave = () => setMessage('bye');

    const[color, setColor] = useState('black');
    
    return(
    	<div> 
            <button onClick={onClickEnter}>입장</button>
            <button onClick={onClickLeave}>퇴장</button>
            <h1 style={{ color }}>{message}</h1>
        	<button style={{ color: 'red' }} onClick={() => setColor('red')}>
            빨간색
            </button>
            <button style={{ color: 'green' }} onClick={() => setColor('green')}>
            초록색
            </button>
        </div>
    );      
};
export default Say;

// 부모 컴포넌트
import Say from './Say';

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

export default App;

state를 사용할 때 주의 사항 

  • state 값을 바꾸어야 할 때는 setState 혹은 useState를 통해 전달받은 세터(Setter) 함수를 사용해야 한다 
  • 배열이나 객체를 업데이트해야 할 때는 배열이나 객체 사본을 만들고 그 사본에 값을 업데이트한 후 , 그 사본의 상태를 setState 혹은 세터(Setter) 함수를 통해 업데이트해주어야 한다 
/* 잘못된 코드 */
// 클래스형 컴포넌트 에서 .. 
this.state.number = this.state.number +1;
this.state.array = this.array.push(2);
this.state.object.value = 5;
// 함수형 컴포넌트에서 .. 
const [ object, setObject] = useState({ a:1, b:1 });
object.b = 2;

// 제대로 된 코드
/*
 객체 다루기
 객체에 대한 사본을 만들때는 spread 연산자라 불리는 ... 을 사용해서 처리한다
*/
const object = { a:1, b:2, c:3 };
const nextObject = { ...object, b:2 }; // 사본을 만들어서 b 값만 덮어 쓴다

/*
 배열 다루기
 배열에 대한 사본을 만들때는 배열의 내장 함수를 활용한다
*/ 
const array = [
	{ id: 1, value: true },
    { id: 2, value: true },
    { id: 3, value: false }
];
let nextArray = array.concat({ id: 4 }); // 새 항목 추가
nextArray.filter(item = > item.id !== 2); // id가 2인 항목 제거
// id 가 1인 항목의 value 를 false로 설정
nextArray.map(item = > item.id === 1 ? { ...item, value : false } : item));
728x90