React - state

정원·2023년 1월 25일
0

React

목록 보기
6/42

2023.01.25 state

리액트 컴포넌트는 입력과 출력이 있다.
입력(prop)을 통해 입력된 데이터를 컴포넌트 함수가 처리해서
return 값을 만들면 return 값이 새로운 ui가 된다.

prop과 함께 컴포넌트 함수를 다시 실행해서
새로운 return값을 만들어주는 또 하나의 데이터가 state이다.

  • prop과 state의 차이점 :
    prop은 컴포넌트를 사용하는 외부자를 위한 데이터고
    state는 컴포넌트를 만드는 내부자를 위한 데이터이다.

li 제목 클릭 시 해당 본문나오게 만들기

mode,content 변수 선언.

mode에 따라 Article내용 변경할 수 있게 if문 선언.

function App() {
  const mode = 'WELCOME';
  const topics = [
    {id:1, title: 'html', body:'html is...'},
    {id:2, title: 'css', body:'css is...'},
    {id:3, title: 'jsvascript', body:'jsvascript is...'},
  ]
  let content = null;
  if(mode === 'WELCOME'){
    content = <Article title="Welcome" body="Hello, WEB"></Article>
  } else if(mode === 'READ') {
    content = <Article title="Read" body="Hello, Read"></Article>
  }
  return (
      <div>
        <Header title="REACT" onChangeMode={()=>{
          alert('Header');
        }}></Header>
        <Nav topics={topics} onChangeMode={(id)=>{
          alert(id);
        }}></Nav>
        {content}
      </div>
  );
}

mode에 따라 내용이 변경된다.

mode = 'WELCOME'

mode = 'READ'


이제 mode의 값을 이벤트가 발생했을때 변경될 수 있게 만들어보자.

return (
      <div>
        <Header title="REACT" onChangeMode={()=>{
          // alert('Header');
          mode = 'WELCOME'
        }}></Header>
        <Nav topics={topics} onChangeMode={(id)=>{
          // alert(id);
          mode = 'READ'
        }}></Nav>
        {content}
      </div>
  );

이벤트가 발생했을때 mode를 변경되게 코드를 수정했다.
하지만 요소를 클릭해도 내용은 변경되지 않는다.

왜냐하면 값을 바꾸긴 했지만 App()함수는 다시 실행되지 않기 때문에
return 값에 변화가 없는 것이다.

mode에 값이 바뀌면 컴포넌트 함수가 새로 실행되면서
새로운 return값을 생성하고 return값이 새로운 ui에 반영되어야한다.

이럴때 state를 사용한다.


state 사용

state를 사용할때는 import를 하고 useState라는 훅을 사용한다.

import { useState } from 'react';

그 후 mode는 지역변수인데 이 변수를
state(상태)로 업그레이드를 시킬 것이다.
userState사용하면 상태가 return된다.

const _mode = useState('WELCOME');
console.log('_mode', _mode);

console에 _mode를 찍어보면
ERROR가 발생하고 그 내용을 살펴보자.

0 번째 원소는 'WLECOME'이다.
1 번째 원소는 함수다.

userState를 하면 배열을 return한다.
그 배열의
0 번째 원소는 상태의 값을 읽을때 쓰는 데이터
1 번째 원소는 그 상태의 값을 변경할때 쓰는 함수이다.


const[mode,setMode] = useState('WELCOME');

  • const _mode = useState('WELCOME');
    : useState의 인자('WELCOME')은 그 state의 초기값이다.

  • const mode = _mode[0];
    : state의 값은 0번째 인덱스값으로 읽는다.

  • const setMode = _mode[1];
    : state의 값을 변경할때는 1번째 인덱스값으로(함수) 바꾼다.

위의 3줄을 아래 1줄로 바꿀수 있다.

const [mode,setMode] = useState('WELCOME');


위에 내용에 따라 App ( ) 수정
값을 바꿀때는 setMode를 사용.

function App() {
  // const _mode = useState('WELCOME');
  // const mode = _mode[0];
  // const setMode = _mode[1];

  const [mode,setMode] = useState('WELCOME')
  ...
  let content = null;
  if(mode === 'WELCOME'){
    content = <Article title="Welcome" body="Hello, WEB"></Article>
  } else if(mode === 'READ') {
    content = <Article title="Read" body="Hello, Read"></Article>
  }
  return (
      <div>
        <Header title="REACT" onChangeMode={()=>{
          // alert('Header');
          // mode = 'WELCOME' 값을 바꿀때는 setMode를 사용한다.
          setMode('WELCOME');
        }}></Header>
        <Nav topics={topics} onChangeMode={(id)=>{
          // alert(id);
          // mode = 'READ' 
          setMode('READ');
        }}></Nav>
        {content}
      </div>
  );
}

수정하면 mode에 따라 내용이 바뀐다.

Nav를 클릭 하면 setMode로 인해 mode가 'READ'로 변경된 후
App( ) 컴포넌트가 다시 실행되고
useState가 mode의 값을 'READ'로 세팅하고
mode가 'READ'이기 때문에 Article의 내용이 변경된다.

✨ mode와 setMode 이름은 사용자가 지정한다.


li마다 본몬 다르게 만들기

이제 Nav를 클릭 할 때마다 해당 제목에 맞는 본문내용을 띄워보자.

어떤 글을 선택했는지 그것을 state로 만들 필요가 있다.

id,setId 변수 선언.
현재 값이 선택되지 않았기 때문에 null

const [id,setId] = useState(null);

onChangeMode 매개변수로 _id를 받고 setId를 통해 id를 변경

 <Nav topics={topics} onChangeMode={(_id)=>{
          setMode('READ');
          setId(_id);
        }}></Nav>

mode가 'READ'일때
반복문 이용해서 선택한 id(state)와 일치하는 li의 id를 찾아서 그 값을 얻어와서
content 내용 변경.

 if(mode === 'WELCOME'){
    content = <Article title="Welcome" body="Hello, WEB"></Article>
  } else if(mode === 'READ') {
    let title, body = null;
    //title,body 초기화
    for(let i=0; i<topics.length; i++) {
      if(topics[i].id === id) {
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = <Article title={title} body={body}></Article>
  }

이렇게 수정했는데 아무 변화가 없다.
디버깅을 해보자.


console.log를 이용해 id를 찍어보면
topics의 id는 숫자, id(state) 값이 숫자가 아닌 문자열로 나온다.
왜그럴까???

id는 setId로 부터온다.
setId는 App( )의 onChangeMode={(_id)} 로 얻어온다.
_id는 Nav 컴포넌트안에 있다.

Nav컴포넌트를 확인해보면
event.target.id로 id를 얻고
a태그의 속성으로 지정하면 숫자가 문자열로 바뀐다.

그렇기 때문에 문자열을 숫자로 컨버팅해줘야한다.

  • Number 함수 : 자바스크립트함수. 문자열 -> 숫자

이렇게 하면 문자열이 숫자로 변경되고
li마다 다른 본몬이 나오는걸 확인할 수 있다.


✨ 전체코드

import logo from './logo.svg';
import './App.css';
import { useState } from 'react';

function Header(props) {
  return <header>
      <h1><a href='/' onClick={(event)=>{
        event.preventDefault();
        props.onChangeMode();
      }}>{[props.title]}</a></h1>
    </header>
}

function Nav(props){
   const lis = [   ]
   for(let i=0; i<props.topics.length; i++) {
    let t = props.topics[i];
    lis.push(<li key={t.id}>
      <a id={t.id} href={'/read/'+t.id} onClick={(event)=>{
        event.preventDefault();
        props.onChangeMode(Number(event.target.id));
      }}>{t.title}</a>
      </li>)
   }
  return <nav>
      <ol>
        {lis}
      </ol>
    </nav>
}
function Article(props) {
  return <article>
      <h2>{props.title}</h2>
      {props.body}
    </article>
}

function App() {
  // const _mode = useState('WELCOME');
  // const mode = _mode[0];
  // const setMode = _mode[1];

  const [mode, setMode] = useState('WELCOME');
  
  // console.log('_mode', _mode);
  
  //li클릭시에 state로 변경하기 위해 id,setId 변수선언, 현재 값이 선택되지 않았기 때문에 null
  const [id, setId] = useState(null);

  const topics = [
    {id:1, title: 'html', body:'html is...'},
    {id:2, title: 'css', body:'css is...'},
    {id:3, title: 'jsvascript', body:'jsvascript is...'},
  ]

  let content = null;

  if(mode === 'WELCOME'){
    content = <Article title="Welcome" body="Hello, WEB"></Article>
  } else if(mode === 'READ') {
    let title, body = null; //title,body 초기화
    //반복문 이용해서 선택한 id(state)와 일치하는 li의 id를 찾아서 그 값을 얻어옴
    for(let i=0; i<topics.length; i++) {
      console.log(topics[i].id, id);
      if(topics[i].id === id) {
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = <Article title={title} body={body}></Article>
  }
  return (
      <div>
        <Header title="REACT" onChangeMode={()=>{
          // alert('Header');
          // mode = 'WELCOME' 값을 바꿀때는 setMode를 사용한다.
          setMode('WELCOME');
        }}></Header>
        <Nav topics={topics} onChangeMode={(_id)=>{
          // alert(id);
          // mode = 'READ' 
          setMode('READ');
          //onChangeMode 매개변수로 _id를 받고 setId를 통해 id를 변경
          setId(_id);
        }}></Nav>
        {content}
      </div>
  );
}

export default App;

0개의 댓글