본문 바로가기
개인 공부/프론트

[React] React.js 입문 - 2

by 육츠 2024. 9. 2.
Contents 접기

화면 상의 데이터를 컨트롤 하는 방법

Counter 실습

버튼을 사용하여 동적으로 변경되는 값을 p태그에 출력

import React, {useState} from 'react';

const Counter = () => {
    const [num, setNumber] = useState(0);
    
    return (
        <div>
            <button>+1</button>
            <button>-1</button>
            <p></p>
        </div>
    )
}
state 동적으로 변경되는 값
useState 동적으로 변경되는 값을 관리하기 위한 함수
const [num, setNumber] = useState(0); const num = 0; 과 같다.
0을 기본값으로 갖는 변수이다.
num

setNumber
num 은 useState 로 인해 0 이다.

num이라는 변수에 대한 setter 함수

 

Counter.js

import React, {useState} from 'react';

const Counter = () => {
    const [num, setNumber] = useState(0);
    // 배열구조
    // const num = 0; 과 같다.
    // setNumber : num이라는 변수에 대한 setter 함수

    const increase = () => {
        setNumber(num + 1);
        // num += 1;  과 같다.
        // 반드시 setter 함수를 사용해야함
    }

    const decrease = () => {
        setNumber (num - 1);
    }

    return (
        <div>
        	{/* onClick 은 반드시 철자를 정확히 */}
            <button onClick={increase}>+1</button>
            <button onClick={decrease}>-1</button>
            <p>{num}</p>
        </div>
    )
}

export default Counter;
   
    const increase = () => {
        setNumber(num + 1);
        // num += 1;  과 같다.
    }
반드시 setter 함수인 setNumber 를 사용 해야한다.

 

App.js

import React from "react";
import {Routes, Route, Link} from 'react-router-dom';

import Home from "./pages/Home";
import About from "./pages/About";
import Counter from "./pages/Counter";


function App() {
  return (
    <div className="App">
      <nav>
        {/* a 태그 처럼 사용된다. */}
        <Link to="/">Home</Link> | <Link to="/about">About</Link> | <Link to="/counter">Counter</Link>
      </nav>
      <Routes>
        {/* 브라우저 패스가 바뀔 때 마다 어떤 컴포넌트를 매칭할지 정의 해야함*/}
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/counter" element={<Counter />} />
      </Routes>
    </div>
  );
}

export default App;

 

.App {
  padding: 20px;
}

index.css 에서 강제로 변경한 것. (사유 : 시각적 불편함)

 

Input 실습

Input.js

import React, {useState} from 'react';

const Input = () => {
    const [textValue, setTextValue] = useState("");
    // 초기값은 빈 배열

    const onChange = (e) => {
        // event를 가지고 온다.
        // e.target = input 태그
        setTextValue(e.target.value)
    }

    return (
        <div>
            {/* onChange 변경이 일어날 때 마다 */}
            <input type="text" value="" onChange={onChange} />
            <br />
            <p>{textValue}</p>
            {/* 현재 키워딩 하는 애로 바뀌고 있음. value 연결 잊지 말기 */}

        </div>
    )
}

export default Input;

 

    return (
        <div>
            {/* onChange 변경이 일어날 때 마다 */}
            <input type="text" value={textValue} onChange={onChange} />
            <br />
            <p>{textValue}</p>
            {/* 현재 키워딩 하는 애로 바뀌고 있음. value 연결 잊지 말기 */}

        </div>
    )

value 값을 연결해줘야 제대로 mapping 시켜주는것.

 

 

Input2 - input 이 많아진다면..

input2.js

import React, {useState} from 'react';

const Input2 = () => {

    const[inputs, setInputs] = useState({
        // object 형태로 정의
        name: "",
        email: "",
        tel: ""
    });

    const {name, email, tel} = inputs;

    const onChange = (e) => {
        const value = e.target.value;
        const id = e.target.id;

        // inputs[id] = value => 상태관리가 되지 않음. 
        // 변경되었다는 것을 인지 할 수 있도록 해야함
        // 자바스크립트의 기본 구조 이해가 필요하다. 
        // 리액트는 참조값만 알고 있는것일 뿐 블록의 상태를 알 수 없다.

        setInputs({
            // 깊은 복사를 해서 spread 기법에 넣어준 후 새로운 object를 만든것
            ...inputs,
            [id] : value 
        })

    }


    return (
        <div>
            <div>
                <label>이름</label>
                <input type="text" id="name" value={name} onChange={onChange} />
            </div>
            <div>
                <label>이메일</label>
                <input type="email" id="email" value={email} onChange={onChange} />
            </div>
            <div>
                <label>전화번호</label>
                <input type="tel" id="tel" value={tel} onChange={onChange} />
            </div>
            <p>이름 : {name}</p>
            <p>이메일 : {email}</p>
            <p>전화번호 : {tel}</p>
        </div>

    )
}

export default Input2;
   
    const[inputs, setInputs] = useState({
        // object 형태로 정의
        name: "",
        email: "",
        tel: ""
    });

    const {name, email, tel} = inputs;
한 번 빼내서 사용해 주어야 한다.
const onChange = (e) => {
        const value = e.target.value;
        const id = e.target.id;

        setInputs({
            // 깊은 복사를 해서 spread 기법에 넣어준 후 새로운 object를 만든것
            ...inputs,
            [id] : value 
        })
id / name 을 가진 태그 값을 가져와서 깊은 복사 후
새로운 object를 만들어 준다.

...inputs 는 name: "", email: "", tel: "" 의 형식으로 들어온다.

 

List 실습

배열로 들어오는 멀티 data를 rendering 처리

List.js

import React from 'react';

// property로 받는다
const User = ({userData}) => {
    return(
        <tr>
            <td>{userData.name}</td>
            <td>{userData.email}</td>
        </tr>
    )

}

const UserList = () => {
    // 실무에서는 배열로 받아온 데이터이다
    const users = [
        {email: 'user1@gmail.com', name: 'user1'},
        {email: 'user2@gmail.com', name: 'user2'},
        {email: 'user3@gmail.com', name: 'user3'},
        {email: 'user4@gmail.com', name: 'user4'}
    ];

    return(
        <table>
            <thead>
                <tr>
                    <th>이름</th>
                    <th>이메일</th>
                </tr>
            </thead>
            <tbody>
                {/* map 함수를 사용하여 요소 하나하나가 들어온다. */}
                {/* <User userData={user} userData : propery명 */}
                {users.map(user => <User userData={user} />)}
            </tbody>
        </table>
    )
}

export default UserList;
// property로 받는다
const User = ({userData}) => {
    return(
        <tr>
            <td>{userData.name}</td>
            <td>{userData.email}</td>
        </tr>
    )

}
자식 컴포넌트

프로퍼티를 사용하여 데이터가 하나씩 던지면
전달 받은 userData 의 이름과 이메일을 가져오면 됨.


return(
        <table>
            <thead>
                <tr>
                    <th>이름</th>
                    <th>이메일</th>
                </tr>
            </thead>
            <tbody>
                {/* <User userData={user} userData : propety명 */}
                {users.map(user => <User userData={user} />)}
            </tbody>
        </table>
    )
map 함수를 이용하여 data가 하나하나씩 user로 들어온다.
배열의 수 만큼 돌린다.

 

property 프로퍼티 란?

속성.

상위 컴포넌트가 하위 컴포넌트에 값을 전달할 때 사용한다. 단방향 데이터 흐름.

문자열을 전달할 때에는 큰 따옴표 " ", 문자열 외에는 중괄호 { } 사용
        - 위 List.js 실습 때에도 User = ({userData}) 에 { } 를 적지 않아서 값이 출력되지 않았었다.

 

App.js

App.js 는 spring의 Controller 역할을 하는 것 같다.

import React from "react";
import {Routes, Route, Link} from 'react-router-dom';

import Home from "./pages/Home";
import About from "./pages/About";
import Counter from "./pages/Counter";
import Input from "./pages/Input";
import Input2 from "./pages/Input2";
import List from "./pages/List";


function App() {
  return (
    <div className="App">
      <nav>
        {/* a 태그 처럼 사용된다. */}
        <Link to="/">Home</Link> |{" "}
        | <Link to="/about">About</Link> | {" "}
        | <Link to="/counter">Counter</Link> | {" "}
        | <Link to="/input">Input</Link> | {" "}
        | <Link to="/input2">Input2</Link> | {" "}
        | <Link to="/list">List</Link>
      </nav>
      <Routes>
        {/* 브라우저 패스가 바뀔 때 마다 어떤 컴포넌트를 매칭할지 정의 해야함*/}
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/counter" element={<Counter />} />
        <Route path="/input" element={<Input />} />
        <Route path="/input2" element={<Input2 />} />
        <Route path="/list" element={<List />} />
      </Routes>
    </div>
  );
}

export default App;