티스토리 뷰

728x90
반응형
React 기본

React 기본

React 기본

React 사용자 입력 처리

한 줄 입력 처리

React 에서 state 를 활용하여 input 태그의 value 값을 초기화 해주거나 변경해 줄 수 있다.

import { useState } from "react";

const ReportEditor = () => {
  const [author, setAuthor] = useState("espania");	//author state 초기화

  return (
    <div className="ReportEditor">
      <h2>오늘의 보고</h2>
      <div>
      	작성자
        <input
          value={author}
          onChange={(e) => {
            setAuthor(e.target.value);	//setAuthor를 활용하여 author의 값을 변경
          }}
        />
      </div>
    </div>
  );
};

export default ReportEditor;

input 태그의 value 값을 state(author) 로 설정 하게 되면 setState(setAuthor) 함수를 통해 state(author) 값을 바꾸지 않는 이상 input 태그의 value 값을 변경하지 못한다.

따라서, setState(setAuthor) 를 onChange 의 콜백 함수에서 실행하여 input 태그의 값이 변경 될 때 마다 state(author) 를 변경해 주어야 한다.

여러 줄 입력 처리

React 에서 state 를 활용하여 textarea 태그의 value 값을 초기화 해주거나 변경 해 줄 수 있다.

import { useState } from "react";

const ReportEditor = () => {
  const [content, setContent] = useState("본문 내용");
  return (
    <div className="ReportEditor">
      <h2>오늘의 보고</h2>
      <div>
        내용
        <textarea
          value={content}
          onchange={(e) => {
            setContent(e.target.value);
          }}
        />
      </div>
    </div>
  );
};

export default ReportEditor;

한 줄 입력 처리와 동일 하다.

state 공통 처리

한 줄 입력 처리와 여러 줄 입력 처리를 공통으로 처리하는 방법을 배워보자

import { useState } from "react";

const ReportEditor = () => {
  const [state, setState] = useState({
    author: "espania",
    content: "본문 내용"
  });
	const handleChangeState = (e) => {
    setState({
      ...state,
      [e.target.name]: e.target.value
    });
	};
  return (
    <div className="ReportEditor">
      <h2>오늘의 보고</h2>
      <div>
        작성자
        <input
          value={state.author}
          onChange={handleChangeState}
        />
      </div>
      <div>
        내용
        <textarea
          value={state.content}
          onChange={handleChangeState}
        />
      </div>
    </div>
  );
};

export default ReportEditor;

이와 같이 state 변수를 여러개 만들지 않고, 하나의 state 변수를 사용하여 처리한다.

onChange 함수에 CallBack 함수로 handleCahngeState 를 전개연산자 활용하여 정의함으로써 onChange 함수가 호출 될 때 마다 state 객체의 모든 속성(author, content) 을 초기화 하지 않도록 한다.

선택 박스 입력 처리

import { useState } from "react";

const ReportEditor = () => {
  const [state, setState] = useState({
    grade: 1
  });

  const handleChangeState = (e) => {
    setState({
      ...state,
      [e.target.name]: e.target.value
    });
  };
  return (
    <div className="ReportEditor">
      <h2>오늘의 보고</h2>
      <div>
        평가
        <select name="grade" value={state.grade} onChange={handleChangeState}>
          <option value={1}>1</option>
          <option value={2}>2</option>
          <option value={3}>3</option>
          <option value={4}>4</option>
          <option value={5}>5</option>
        </select>
      </div>
    </div>
  );
};

export default ReportEditor;

React Dom 조작 / useRef

개요

HTML 태그 들의 유효성 검사(정상적으로 입력이 되었는지 확인) 를 하여 태그를 focus 할 수 있다.

UseRef

Dom 요소를 선택할 수 있는 기능

import { useRef, useState } from "react";

const ReportEditor = () => {
  const authorInput = useRef();	//userRef 를 사용하여 DOM 선택 변수 생성
  const contentInput = useRef();

  const [state, setState] = useState({
    author: "",
    content: "",
    grade: 1
  });

  const handleChangeState = (e) => {
    setState({
      ...state,
      [e.target.name]: e.target.value
    });
  };

  const handleSubmit = () => {
    if (state.author.length < 1) {
      authorInput.current.focus();	//해당 변수에 해당하는 DOM 객체 focus
      return;
    }

    if (state.content.length < 5) {
      contentInput.current.focus(); //해당 변수에 해당하는 DOM 객체 focus
      return;
    }

    console.log(state);
    alert("저장 성공!");
  };

  return (
    <div className="ReportEditor">
      <h2>오늘의 보고</h2>
      <div>
        <input
          ref={authorInput}	//useRef 변수를 ref 속성에 대입
          value={state.author}
          onChange={handleChangeState}
          name="author"
          placeholder="작성자"
          type="text"
        />
      </div>
      <div>
        <textarea
          ref={contentInput}
          value={state.content}
          onChange={handleChangeState}
          name="content"
          placeholder="보고"
          type="text"
        />
      </div>
      <div>
        <span>오늘의 평가점수 : </span>
        <select name="grade" value={state.grade} onChange={handleChangeState}>
          <option value={1}>1</option>
          <option value={2}>2</option>
          <option value={3}>3</option>
          <option value={4}>4</option>
          <option value={5}>5</option>
        </select>
      </div>
      <div>
        <button onClick={handleSubmit}>보고 저장하기</button>
      </div>
    </div>
  );
};
export default ReportEditor;

UseRef 를 사용하여 DOM 요소를 선택할 수 있는 변수를 만들고 해당 변 수를 tag 의 ref 속성으로 지정해주면, useRef변수.current.focus 로 해당 객체를 접근 할 수 있다.

React List 조회 / rendering

개요

부모 tag 에서 전달 받은 데이터를 리스트 형태로 출력해보자

App.js (부모 Tag)

import "./App.css";
import ReportList from "./ReportList";

const App = () => {
  const dummyList = [
    {
      id: 1,
      author: "espania",
      content: "하이",
      grade: 1
    },
    {
      id: 2,
      author: "권영욱",
      content: "하이2",
      grade: 2
    },
    {
      id: 3,
      author: "권기웅",
      content: "하이3",
      grade: 3
    }
  ];
  return (
    <div className="App">
      <ReportList reportList={dummyList} />
    </div>
  );
};
export default App;

RepotList (자식 태그)

const ReportList = ({ reportList }) => {
  return (
    <div>
      <h2>보고 리스트</h2>
      <div>
        {reportList.map((it) => {
          return (
            <div key={it.id}>
              <div>
                <span>작성자 : {it.author}</span>
              </div>
              <div>
                <span>내용 : {it.content}</span>
              </div>
              <div>
                <span>보고 : {it.grade}</span>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
};

export default ReportList;

배열의 map 함수로 dummyList 배열을 list 형태로 출력 할 수 있다.

React 데이터 추가 / state 끌어올리기

개요

React 에서 버튼 이벤트를 통해 데이터를 추가해 보자!

배열 리스트의 데이터를 동적으로 추가하 조회해 보자!

Component / 구조

React 는 단방향 으로만 데이터가 흐르기 때문에 같은 level 에 있는 Component 끼리 데이터를 주고 받을 수 있도록, 공통 부모의 state 를 활용한 state 끌어올리기 를 통해 데이터를 제어한다.


state 끌어올리기 를 통해 공통 부모 Component 의 state Event(SetData) 는 아래에서 위로, DATA(Data)는 위에서 아래로의 데이터 흐름을 가진다.

App.js

import { useState, useRef } from "react";
import ReportEditor from "./ReportEditor";
import ReportList from "./ReportList";

const App = () => {
  const [data, setData] = useState([]);
  const dataId = useRef(0);

  const onCreate = (author, content, grade) => {
    const newItem = {
      author,
      content,
      grade,
      id: dataId.current
    };
    dataId.current += 1;
    setData([newItem, ...data]);
  };

  return (
    <div className="App">
      <ReportEditor onCreate={onCreate} />	//onCreate 메소드 전달
      <ReportList reportList={data} />	//data State 전달
    </div>
  );
};
export default App;
  • App.js

    ReportEditor.js , ReportList.js 의 부모 Component

    ReportEditor.js 에서 보고서 추가

    ReportList.js 에서 보고서 리스트 출력

  • State 끌어올리기

    ReportEditor.js 에는 onCreate method(EVENT) 를 prop 으로 전달

    ReportList.js 에는 data State(DATA) 를 prop 으로 전달

ReportEditor.js

import { useState, useRef } from "react";

const ReportEditor = ({ onCreate }) => {
  const authorInput = useRef();
  const contentInput = useRef();

  const [state, setState] = useState({
    author: "",
    content: "",
    grade: 1
  });

  const handleChangeState = (e) => {
    setState({
      ...state,
      [e.target.name]: e.target.value
    });
  };

  const handleSubmit = () => {
    if (state.author.length < 1) {
      authorInput.current.focus();
      return;
    }

    if (state.content.length < 5) {
      contentInput.current.focus();
      return;
    }
    onCreate(state.author, state.content, state.grade);
    alert("저장 성공");
    setState({
      author: "",
      content: "",
      grade: 1
    });
  };

  return (
    <div className="ReportEditor">
      <h2>오늘의 보고</h2>
      <div>
        작성자
        <input
          ref={authorInput}
          value={state.author}
          onChange={handleChangeState}
          name="author"
        />
      </div>
      <div>
        <textarea
          ref={contentInput}
          value={state.content}
          onChange={handleChangeState}
          name="content"
          type="text"
        />
      </div>

      <div>
        <span>오늘의 평가점수 : </span>
        <select name="grade" value={state.grade} onChange={handleChangeState}>
          <option value={1}>1</option>
          <option value={2}>2</option>
          <option value={3}>3</option>
          <option value={4}>4</option>
          <option value={5}>5</option>
        </select>
      </div>
      <div>
        <button onClick={handleSubmit}>보고 저장하기</button>
      </div>
    </div>
  );
};
export default ReportEditor;
  • ReportEditor.js

    App.js 에서 prop 으로 onCreate Method(EVENT) 전달 받음

    새로운 보고서를 작성하여 저장 버튼을 누르면 onCreate Method 호출

    App.js 의 data State 의 값 을 추가

ReportList.js

import ReportItem from "./ReportItem";

const ReportList = ({ reportList }) => {
  return (
    <div>
      <h2>보고 리스트</h2>
      {reportList.length}개의 보고가 있습니다.
      <div>
        {reportList.map((it) => {
          return <ReportItem key={it.id} {...it} />;
        })}
      </div>
    </div>
  );
};

export default ReportList;
  • ReportList.js

    App.js 에서 prop 으로 data State(DATA) 전달 받음

    data State 가 변경되면 ReportList.js re-rendering 후 보고서 리스트 출력

React 데이터 삭제 / filter

개요

React 에서 Button Event 를 활용하여 데이터를 삭제해보자

배열 리스트의 데이터를 동적으로 삭제하여 조회해보자

배열의 filter 함수를 통한 데이터 삭제 스킬을 배워보자

App.js

import { useState, useRef } from "react";
import ReportEditor from "./ReportEditor";
import ReportList from "./ReportList";

const App = () => {
  const [data, setData] = useState([]);
  const dataId = useRef(0);

  const onCreate = (author, content, grade) => {
    const newItem = {
      author,
      content,
      grade,
      id: dataId.current
    };
    dataId.current += 1;
    setData([newItem, ...data]);
  };

  const onDelete = (targetId) => {
    const newReportList = data.filter((it) => it.id !== targetId);	//filter 메소드 사용!!
    setData(newReportList);
  };
  
  return (
    <div className="App">
      <ReportEditor onCreate={onCreate} />
      <ReportList onDelete={onDelete} reportList={data} />
    </div>
  );
};
export default App;
  • App.js

    삭제 이벤트(Ondelete) 를 ReportList.js 의 prop 으로 전달

    data State 를 filter method 로 초기화

ReportList.js / ReportItem.js

import ReportItem from "./ReportItem";

const ReportList = ({ onDelete, reportList }) => {
  return (
    <div>
      <h2>보고 리스트</h2>
      {reportList.length}개의 보고가 있습니다.
      <div>
        {reportList.map((it) => {
          return <ReportItem key={it.id} {...it} onDelete={onDelete} />;
        })}
      </div>
    </div>
  );
};

export default ReportList;
  • ReportList.js

    App.js → ReportList.js 로 onDelete Method 전달

ReportItem.js

const ReportItem = ({ onDelete, id, author, content, grade }) => {
  return (
    <div className="ReportItem">
      <div className="info">
        <span>
          작성자 : {author} | 점수 : {grade}{" "}
        </span>
        <div className="content">{content}</div>
        <button
          onClick={() => {
            console.log(id);
            if (window.confirm(`${id}번째 보고를 정말 삭제할까요?`)) {
              onDelete(id);	//onDelete 메소드 호출 !!!
            }
          }}
        >
          삭제하기
        </button>
      </div>
    </div>
  );
};

export default ReportItem;
  • ReportItem.js

    ReportList.js → ReportItem.js 로 onDelete Method 전달

    onDelete Method 호출

React 데이터 수정 / map

개요

React 에서 Button Event 를 통해 데이터를 수정해보자

toggle state 를 활용하여 수정 폼을 자유롭게 변경해보자

배열의 map 함수를 통한 데이터 수정 스킬을 배워보자

App.js

import { useState, useRef } from "react";
import ReportEditor from "./ReportEditor";
import ReportList from "./ReportList";

const App = () => {
  const [data, setData] = useState([]);
  const dataId = useRef(0);

  const onCreate = (author, content, grade) => {
    const newItem = {
      author,
      content,
      grade,
      id: dataId.current
    };
    dataId.current += 1;
    setData([newItem, ...data]);
  };

  const onDelete = (targetId) => {
    console.log(`${targetId}가 삭제되었습니다`);
    const newReportList = data.filter((it) => it.id !== targetId);
    setData(newReportList);
  };

  const onEdit = (targetId, newContent) => {
    setData(
      data.map((it) =>
        it.id === targetId ? { ...it, content: newContent } : it
      )
    );
  };
  return (
    <div className="App">
      <ReportEditor onCreate={onCreate} />
      <ReportList onEdit={onEdit} onDelete={onDelete} reportList={data} />
    </div>
  );
};
export default App;
  • App.js

    수정 이벤트(OnEdit) 를 ReportList.js 의 prop 으로 전달

    data State 를 map method 로 초기화

ReportList.js / ReportItem.js

import ReportItem from "./ReportItem";

const ReportList = ({ onEdit, onDelete, reportList }) => {
  return (
    <div>
      <h2>보고 리스트</h2>
      {reportList.length}개의 보고가 있습니다.
      <div>
        {reportList.map((it) => {
          return (
            <ReportItem
              key={it.id}
              {...it}
              onDelete={onDelete}
              onEdit={onEdit}
            />
          );
        })}
      </div>
    </div>
  );
};

export default ReportList;
  • ReportList.js

    App.js → ReportList.js 로 onEdit Method 전달

import { useState, useRef } from "react";

const ReportItem = ({ onEdit, onDelete, id, author, content, grade }) => {
  const [isEdit, setIsEdit] = useState(false);
  const [localContent, setLocalContent] = useState(content);
  const localContentInput = useRef();

  const toggleIsEdit = () => {
    setIsEdit(!isEdit);
  };
  const HandleRemove = () => {
    console.log(id);
    if (window.confirm(`${id}번째 보고를 정말 삭제할까요?`)) {
      onDelete(id);
    }
  };
  const HandleContent = (e) => {
    setLocalContent(e.target.value);
  };
  const handleQuitEdit = () => {
    setIsEdit(false);
    setLocalContent(content);
  };
  const handleEdit = () => {
    if (localContent.length < 5) {
      localContentInput.current.focus();
      return;
    }
    if (window.confirm("수정하겠습니까?")) {
      onEdit(id, localContent);
      toggleIsEdit();
    }
  };
  return (
    <div className="ReportItem">
      <div className="info">
        <span>
          작성자 : {author} | 점수 : {grade}{" "}
        </span>
        <div className="content">
          {isEdit ? (
            <textarea
              ref={localContentInput}
              value={localContent}
              onChange={HandleContent}
            />
          ) : (
            content
          )}
        </div>
        {isEdit ? (
          <div>
            <button onClick={handleQuitEdit}>수정 취소</button>
            <button onClick={handleEdit}>수정 완료</button>
          </div>
        ) : (
          <div>
            <button onClick={HandleRemove}>삭제하기</button>
            <button onClick={toggleIsEdit}>수정하기</button>
          </div>
        )}
      </div>
    </div>
  );
};

export default ReportItem;
  • ReportItem.js

    ReportList.js -> ReportItem.js 로 onEdit Method 전달

    onEdit Method 호출

LifeCycle

인간 세계에서의 생애 주기란 시간의 흐름에 따라 변화해가는 개인 생애의 일정한 단계별 과정을 말한다. 기본적으로 역량의 변화 발전에 따라 영유아기, 아동기, 청소년기, 성인기, 노인기로 구분할 수 있다. 이처럼, React Component 도 생애 주기 , Life Cycle 이 존재 한다.

React Component / Life Cycle



class 기반 React Component 에서 생명 주기에 따라 호출하는 함수가 존재 한다.

React Hooks


Class 기반 React Component 에서 사용 하는 생명 주기 함수의 기능을 함수형 React Component 에서 사용할 수 있도록 해주는 기능 이다.


UseEffect

함수형 React Component 에서 Life Cycle 을 제어하기 위해서 UseEffect 라는 Hooks 를 사용한다.

import React, {useEffect} from "react";

useEffect(()=>{
	//to do..
}, []);

첫번째 매개변수

Callback 함수

두번째 매개변수

Dependency Array(의존성 배열) : 배열내에 들어있는 값이 변화하면 Callback 함수 실행

UseEffect 를 사용하여 Component 제어

import React, {useEffect, useState} from "react";

const LifeCycle = () => {
    const [count, setCount] = useState(0);
    const [text, setText] = useState("");

    //Mount
    //dependency array 가 빈 배열일 때
    useEffect(()=>{
        console.log('Mount');
    }, []);

    //Update
    //dependency array 를 전달하지 않을 때
    useEffect(()=>{
        console.log('Update');
    })

    //dependency array에 전달한 배열의 값이 변경되었을 때
    useEffect(()=>{
        console.log(`count is update : ${count}`);;
    }, [count]);

    useEffect(()=>{
        console.log(`text is update : ${text}`);
    }, [text])

    return (
        <div style={{padding:20}}>
            {count}
           <button onClick={()=>{setCount(count+1)}}>+</button>
        
            <div>
                <input value={text} onChange={(e)=>setText(e.target.value)}/>
            </div>
        </div>
    );
};

export default LifeCycle;
  1. mount

    useEffect hooks 의 dependency array 가 빈 배열 일 때, 해당 component 가 mount 될 때, callback 함수가 호출 된다.

    import React, {useEffect, useState} from "react";
    
    const LifeCycle = () => {
        const [count, setCount] = useState(0);
        const [text, setText] = useState("");
    
        //Mount
        //dependency array 가 빈 배열일 때
        useEffect(()=>{
            console.log('Mount');
        }, []);
    
        return (
            <div style={{padding:20}}>
                {count}
               <button onClick={()=>{setCount(count+1)}}>+</button>
            
                <div>
                    <input value={text} onChange={(e)=>setText(e.target.value)}/>
                </div>
            </div>
        );
    };
    
    export default LifeCycle;
  1. update

    useEffect hooks 의 dependency array 에 값을 전달 하지 않거나, dependency array 에 전달한 배열의 값이 변경 되었을 때, callback 함수가 호출 된다.

    import React, {useEffect, useState} from "react";
    
    const LifeCycle = () => {
        const [count, setCount] = useState(0);
        const [text, setText] = useState("");
    
        //Update
        //dependency array 를 전달하지 않을 때
        useEffect(()=>{
            console.log('Update');
        })
    
        //dependency array에 전달한 배열의 값이 변경되었을 때
        useEffect(()=>{
            console.log(`count is update : ${count}`);;
        }, [count]);
    
        useEffect(()=>{
            console.log(`text is update : ${text}`);
        }, [text])
    
        return (
            <div style={{padding:20}}>
                {count}
               <button onClick={()=>{setCount(count+1)}}>+</button>
            
                <div>
                    <input value={text} onChange={(e)=>setText(e.target.value)}/>
                </div>
            </div>
        );
    };
    
    export default LifeCycle;
  1. unmount

    component 의 useEffect hooks 에서 return 하는 함수는 해당 component 가 unmount 될 때 호출된다.

    import React, {useEffect, useState} from "react";
    
    const UnmountTest = () =>{
    
        useEffect(()=>{
            //Mount
            console.log("Mount");
    
            return () => {
                //Unmount
                console.log("Unmount");
            }
        }, []);
    
        return (
            <div>Unmount Testing Component</div>
        )
    }
    
    const LifeCycle = () => {
        const [isVisible, setIsVisible] = useState(false);
        const toggle = () => setIsVisible(!isVisible);
    
        return (
            <div style={{padding:20}}>
                <button onClick={toggle}>ON/OFF</button>
                {isVisible && <UnmountTest/>}
            </div>
        );
    };
    
    export default LifeCycle;

React API 호출

개요

React 에서 API 를 호출 해보자

UseEffect 를 이용하여 Component 가 Mount 되는 시점에 API 의 결과 값을 초기값으로 활용해보자

무료 API 데이터 제공 사이트(jsonplaceholder ) https://jsonplaceholder.typicode.com/

App.js

import { useEffect, useRef, useState } from "react";
import "./styles.css";

export default function App() {
  const [data, setData] = useState([]);
  const dataId = useRef(0);

  const getData = async () => {
    const res = await fetch(
      "https://jsonplaceholder.typicode.com/comments"
    ).then((res) => {
      return res.json();
    });

    const initData = res.slice(0, 20).map((it) => {
      return {
        author: it.email,
        content: it.body,
        emotion: Math.floor(Math.random() * 5) + 1,
        created_date: new Date().getTime(),
        id: dataId.current++
      };
    });

    setData(initData);
  };

  useEffect(() => {
    getData();
    console.log(data);
  }, []);
  //
  return (
    <div className="App">
      <div>
        {data.map((it) => {
          return (
            <div
              style={{
                border: "solid black 1px",
                marginBottom: "10px"
              }}
            >
              <span>작성자: {it.author}</span>
              <span>내용: {it.content}</span>
              <span>감정: {it.emotion}</span>
              <span>작성일: {it.created_date}</span>
              <span>id: {it.id}</span>
            </div>
          );
        })}
      </div>
    </div>
  );
}
  1. data(State) 선언

    보고서 목록 list 배열

  1. getData 함수 선언

    async 함수

    jsonplaceholder 에서 fetch 함수로 API 데이터 호출

    fetch 함수의 결과값을 내부에 initData 로 전달

    initData

    fetch 함수의 결과값을 map 으로 가공

    setData 함수로 data(State) 초기화

  1. getData 호출

    useEffect 사용

    Component 가 Mount 되는 시점에 getData 호출

    data State 초기화

728x90
댓글
반응형
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함