DEVELOP
article thumbnail

React

# React 

:  사용자 정의 태그를 만드는 기술 

-  자바스크립트의 라이브러리

-  사용자 정의 인터페이스를 만들기 위해 사용 

-  https://ko.reactjs.org/

 

React – 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리

A JavaScript library for building user interfaces

ko.reactjs.org

npx create-react-app my-app
cd my-app
npm start

 


컴포넌트

# 컴포넌트

: 사용자 정의 태그 

- UI를 재사용이 가능한 개별적인 여러 조각으로 나누고 각 조각을 개별적으로 살펴볼 수 있음 

- 이름의 시작은 항상 대문자

- 함수 컴포넌트 / 클래스 컴포넌트 

- props 객체를 인자로 받고, 화면에 어떻게 보여줄 것인지를 기술하는 리액트 엘리먼트를 return

 

  < 함수 컴포넌트 예시 > 

 

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header>
        <h1><a href ="/">WEB</a></h1>
      </header>
      <nav>
        <ol>
          <li><a href="/read/1">html</a></li>
          <li><a href="/read/2">css</a></li>
          <li><a href="/read/3">js</a></li>
        </ol>
      </nav>
      <article>
        <h2>Welcome</h2>
        Hellp, WEB! 
      </article>
    </div>
  );
}

export default App;

 

import logo from './logo.svg';
import './App.css';

function Header() {
  return <header>
    <h1><a href="/">REACT</a></h1>
  </header>
}

function Nav(){
  return <nav>
  <ol>
    <li><a href="/read/1">html</a></li>
    <li><a href="/read/2">css</a></li>
    <li><a href="/read/3">js</a></li>
  </ol>
</nav>
}

function Article(){
  return <article>
  <h2>Welcome</h2>
  Hello, WEB!
</article>
}
function App() {
  return (
    <div className="App">
      <Header></Header>
      <Header></Header>
      <Header></Header>
      <Nav></Nav>
      <Article></Article>
    </div>
  );
}

export default App;

프로퍼티(Props)

# 프로퍼티(Props) 

: 상위 컴포넌트가 하위 컴포넌트에게 값 전달시 사용 ( 단방향 데이터 흐름)

- 수정 불가 ( 하위 컴포넌트 기준에서 읽기 전용 데이터) 

- 하위 컴포넌트에서 프로퍼티의 값을 이용해 리액트 엘리먼트를 작성하여 리턴함 

- props는 (함수 매개변수처럼) 컴포넌트에 전달

 

  < 프로퍼티 사용 예시 >

//import logo from './logo.svg';
import './App.css';

function Header(props) {
  return <header>
    <h1><a href="/">{props.title}</a></h1>
  </header>
}

function Nav(props) {
  const topicsList = [];
  for (var i = 0; i < props.topics.length; i++) {
    var t = props.topics[i];
    topicsList.push(<li key={t.id}><a href={'/read/' + t.id}>{t.title}</a></li>);
  }
  return <nav>
    <ol>
      {topicsList}
    </ol>
  </nav>
}

function Article(props) {
  return <article>
    <h2>{props.title}</h2>
    {props.body}
  </article>
}
function App() {
  const topics = [
    { id: 1, title: 'html', body: 'html is...' },
    { id: 2, title: 'css', body: 'css is...' },
    { id: 3, title: 'js', body: 'js is...' },
  ];

  return (
    <div className="App">
      <Header title="React!!"></Header>
      <Header title="RRR"></Header>
      <Header title="EEE"></Header>
      <Nav topics={topics}></Nav>
      <Article title="Welcome" body="Hello,Web"></Article>
    </div>
  );
}

export default App;

이벤트

# 이벤트

- preventDefault()를 호출해주어야 기본 동작 방지 가눙 

      <Header title="React!!" onchangeMode={() => {
        alert('WELCOME');
      }}></Header>
var Header = (props) => {
  return <header>
    <h1><a href="/" onClick={(event) => {
      event.preventDefault(); //기본동작 방지 
      props.onchangeMode();
    }}>{props.title}</a></h1>
  </header>
}

state 

# state 

- 컴포넌트 내부에서 변경 가능한 데이터를 관리해야할 때 사용 

- props는 (함수 매개변수처럼) 컴포넌트에 전달되어 값의 변경이 불가한 반면 state는 (함수 내에 선언된 변수처럼) 컴포넌트 안에서 관리하므로 값의 변경이 가능 

- 보통 이벤트와 함께 사용 

- 동적인 데이터를 다룰 때 사용 

 

 

<state 사용 예시>

const [state, setState] = useState(initialState);
const [ 데이터, 데이터변경함수 ] = useState(초기값(생략가능));

- mode와 id를 state로 사용 

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

var Header = (props) => {
  return <header>
    <h1><a href="/" onClick={(event) => {
      event.preventDefault(); //기본동작 방지 
      props.onchangeMode();
    }}>{props.title}</a></h1>
  </header>
}

var Nav = (props) => {
  const topicsList = [];
  for (var i = 0; i < props.topics.length; i++) {
    var t = props.topics[i];
    topicsList.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>
      {topicsList}
    </ol>
  </nav>
}

var Article = (props) => {
  return <article>
    <h2>{props.title}</h2>
    {props.body}
  </article>
}
var App = () => {
  const [mode, setMode] = useState('WELCOME');
  const [id, setId] = useState(null);
  const topics = [
    { id: 1, title: 'html', body: 'html is...' },
    { id: 2, title: 'css', body: 'css is...' },
    { id: 3, title: 'js', body: 'js is...' },
  ];
  var content = null;
  if(mode==='WELCOME'){
    content = <Article title='Welcome' body = 'Hello, WEB'></Article>
  }else if(mode==='READ'){
    let title, body = null;
    for(var 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>
  }
  return (
    <div className="App">
      <Header title="React!!" onchangeMode={() => {
        setMode('WELCOME');
      }}></Header>
      <Nav topics={topics} onchangeMode={(id)=>{
        setMode('READ');
        setId(id);
      }}></Nav>
      {content}
    </div>
  );
}

export default App;

결과예시


Create 기능 추가 

- 목록에 사용자가 직접 title과 body를 작성하여 추가

 

 < Create 컴포넌트 > 

   - onSubmit() : submit(create)버튼 클릭 시 props.onCreate에 사용자가 작성한 title과 body값을 넘겨줌 

var Create = (props) => {
  return <article>
    <h2>Create</h2>
    <form onSubmit={(event)=>{
      event.preventDefault();
      const title = event.target.title.value;
      const body = event.target.body.value;
      props.onCreate(title,body);
    }}>
      <p>
      <input type="text" name="title" placeholder="title" />
      </p>
      <p>
        <textarea name="body" placeholder='body'></textarea>
      </p>
      <p>
        <input type="submit" value = "Create"/>
      </p>
    </form>
  </article>
}

- topic 배열, 다음 id 값을 각각 state로 지정 

- create 클릭 시 mode가 'CREATE'로 변경됨 

- 새로운 id, title, body 내용을 담은 객체를 생성하고 원래의 topics객체에 push

- 이때 원래의 배열topics에 ... 을 붙여 기존배열을 새로운 배열로 복사하고, 새로운 객체를 push하여 setTopics함 

- 다시 mode를 'READ'로 변경하고, 다음 id값, 현재 id값을 set함

- mode가 READ가 되었으므로 새로운 객체가 추가된 리스트가 화면에 출력 

var App = () => {
  const [mode, setMode] = useState('WELCOME');
  const [id, setId] = useState(null);
  const [topics, setTopics] = useState([
    { id: 1, title: 'html', body: 'html is...' },
    { id: 2, title: 'css', body: 'css is...' },
    { id: 3, title: 'js', body: 'js is...' },
  ]);
  const [nextId, setNextId] = useState(topics.length);
  
  var content = null;
  if (mode === 'WELCOME') {
    content = <Article title='Welcome' body='Hello, WEB'></Article>
  } else if (mode === 'READ') {
    let title, body = null;
    for (var 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>
  } else if (mode === 'CREATE') {
    content = <Create onCreate = {(title,body)=>{
    const newTopic = {id : nextId, title:title, body:body }
    const newTopics = [...topics];
    newTopics.push(newTopic);
    setTopics(newTopics);
    setMode('READ'); 
    setId(nextId);
    setNextId(nextId+1);
    }}></Create>
  }
  return (
    <div className="App">
      <Header title="React!!" onchangeMode={() => {
        setMode('WELCOME');
      }}></Header>
      <Nav topics={topics} onchangeMode={(id) => {
        setMode('READ');
        setId(id);
      }}></Nav>
      {content}
      <a href="/create" onClick={(event) => {
        event.preventDefault();
        setMode("CREATE");
      }}>Create</a>
    </div>
  );
}

결과예시


Update(Edit, 값 수정)

- 사용자가 수정할 항목을 선택해 title과 body 값을 원하는 내용으로 수정하고, 수정한 결과를 화면에 출력

 

< Edit 컴포넌트>

- 원래의 값을 input 칸에 넣어야하는데 그냥 props에서 값을 추출하면 수정이 불가한 값이 됨 

- props의 title과 body값을 각각 state로 바꿔서 수정가능하게 함 

- onChange함수로 input 칸의 값이 수정될때마다 그 값을 각각 title과 body로 set함 

- 수정된 title과 body값을 onEdit의 인자로 넘겨줌 

var Edit = (props) => {
  const [title, setTitle] = useState(props.title);
  const [body, setBody] = useState(props.body);
  return <article>
    <h2>Edit</h2>
    <form onSubmit={(event) => {
      event.preventDefault();
      const title = event.target.title.value;
      const body = event.target.body.value;
      props.onEdit(title, body);
    }}>
      <p>
        <input type="text" name="title" placeholder="title" value={title} onChange={(event)=>{
          setTitle(event.target.value);
        }}/>
      </p>
      <p>
        <textarea name="body" placeholder='body' value={body} onChange = {(event)=>{
          setBody(event.target.value);
        }}></textarea>
      </p>
      <p>
        <input type="submit" value="Edit" />
      </p>
    </form>
  </article>
}

- contextControl으로 mode가 'WELCOME'일 때는 null이다가, 'READ' mode일 때만 Edit 버튼이 보이게 함

- onEdit의 인자로 받은 title과 body로 새 객체를 생성

- 기존 객체배열에서 수정한 객체를 새로운 객체로 바꾸고 mode를 'READ'로 바꿈 

var App = () => {
  const [mode, setMode] = useState('WELCOME');
  const [id, setId] = useState(null);
  const [topics, setTopics] = useState([
    { id: 1, title: 'html', body: 'html is...' },
    { id: 2, title: 'css', body: 'css is...' },
    { id: 3, title: 'js', body: 'js is...' },
  ]);
  const [nextId, setNextId] = useState(topics.length);

  var content = null;
  var contextControl = null; // Read mode일때만 edit 보이도록 

  if (mode === 'WELCOME') {
    content = <Article title='Welcome' body='Hello, WEB'></Article>
  } else if (mode === 'READ') {
    let title, body = null;
    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>
    contextControl = <li><a href={"/edit/" + id} onClick={(event) => {
      event.preventDefault();
      setMode('EDIT');
    }}>Edit</a></li>

  } else if (mode === 'CREATE') {
    content = <Create onCreate={(title, body) => {
      const newTopic = { id: nextId, title: title, body: body }
      const newTopics = [...topics];
      newTopics.push(newTopic);
      setTopics(newTopics);
      setMode('READ');
      setId(nextId);
      setNextId(nextId + 1);
    }}></Create>
  } else if (mode === 'EDIT') {
    let title, body = null;
    for (let i = 0; i < topics.length; i++) {
      if (topics[i].id === id) {
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = <Edit title={title} body={body} onEdit={(title, body) => {
      const newTopics =[...topics];
      const editedTopic = {id:id, title:title, body:body}
      for(let i = 0; i<topics.length; i++){
        if(newTopics[i].id === id){
          newTopics[i] = editedTopic;
          break;
        }
      }
      setTopics(newTopics);
      setMode('READ');
    }}></Edit>
  }
  return (
    <div className="App">
      <Header title="React!!" onchangeMode={() => {
        setMode('WELCOME');
      }}></Header>
      <Nav topics={topics} onchangeMode={(id) => {
        setMode('READ');
        setId(id);
      }}></Nav>
      {content}
      <ul>
        <li><a href="/create" onClick={(event) => {
          event.preventDefault();
          setMode("CREATE");
        }}>Create</a></li>
        {contextControl}
      </ul>
    </div>
  );
}

결과예시


Delete 

- 원하는 항목 선택 후 Delete 버튼 클릭시 해당 항목 삭제

 

- mode가 'READ'일 때 contextControl을 수정하여 delete 버튼 보이게 함

- delete 버튼 클릭하면 빈 배열 newTopics를 생성하고, 선택된 id 값의 객체를 제외한 다른 객체들을 빈 배열에 push

- 새로운 topics배열을 set하고, nextId를 현재 topics의 길이로 설정하고, mode를 'WELCOME'으로 바꿈 

else if (mode === 'READ') {
    let title, body = null;
    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>
    contextControl = <><li><a href={"/edit/" + id} onClick={(event) => {
      event.preventDefault();
      setMode('EDIT');
    }}>Edit</a></li>
    <li><input type="button" value = "Delete" onClick={()=>{
      const newTopics = [];
      for(let i=0; i<topics.length; i++){
        if(topics[i].id !== id){
          newTopics.push(topics[i]);
        }
      }
      setTopics(newTopics);
      setNextId(topics.length);
      setMode('WELCOME');
    }}/></li></>

  }

결과예시

 

profile

DEVELOP

@JUNGY00N