React 기초

abi hong·2023년 7월 21일
0

Frontend

목록 보기
2/12

React 설치

설치 과정에서의 오류 해결
https://velog.io/@jyun9807/react-project-%EC%83%9D%EC%84%B1-error

소스코드 수정방법

소스파일

index.js → 입구 파일, 여기에 작성한 대로 동작하게 된다.

이때, 아래의 코드는

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

App이라는 태그가 id="root"인 태그로 렌더링하라는 코드

소스코드 배포

  • 배포 파일 생성 → npm run build

  • build 폴더에 있는 index.js 파일 실행 → npx serve -s build

컴포넌트 만들기

React는 사용자 정의 태그를 만드는 기술이다.

  • 재사용 가능
  • 코드 분리 가능

props

컴포넌트에 속성(prop)을 어떻게 추가하는지

props는 객체

  • 반복적인 li 태그의 경우
    이때, Nav는 매개변수로 topics 배열을 받는다.

    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 href={'/read/' + t.id}>{t.title}</a></li>)
      }
    
      return <nav>
        <ol>
          {lis}
        </ol>
      </nav>
    }

    자동생성한 태그의 경우, 고유한 key 속성을 가져야한다.

이벤트

<Header title="REACT" onChangeMode={() => {
	alert('Header');
}}></Header>
function Header(props) {
  return <header>
    <h1>
      <a href="/" onClick={(e) => {
          e.preventDefault();
          props.onChangeMode();
      }}>{props.title}</a>
    </h1>
  </header>
}
  • onClick의 callback 함수가 호출될 때, React는 이벤트 객체를 첫번째 파라미터로 주입해준다.
  • e.preventDefault();
    그 태그의 기본동작을 방지해준다. 만약 a태그의 경우, 클릭 시 reload가 일어나지 않는다.

<Nav topics={topics} onChangeMode={(id) => {
	alert(id);
}}/>
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={(e) => {
        e.preventDefault();
        props.onChangeMode(e.target.id);
      }}>{t.title}</a>
    </li>)
  }

  return <nav>
    <ol>
      {lis}
    </ol>
  </nav>
}
  • event.target
    그 이벤트를 유발시킨 태그를 가리킴 여기서는 a 태그를 의미

state

prop과 state 모두 이 값이 변경되면 새로운 return 값을 만들어 UI를 바꾼다.

  • prop의 경우, 컴포넌트를 사용하는 외부자를 위한 데이터
  • state의 경우, 컴포넌트를 만드는 내부자를 위한 데이터

useState()는 배열을 return

const _mode = useState('WELCOME');
const mode = mode[0];
const setMode = mode[1];

// 위 세줄과 동일코드
const [mode, setMode] = useState('WELCOME');
  • useState()의 인자는 상태의 초기 값
  • 배열의 0번째 원소는 상태의 값을 읽을 때 사용하는 변수
  • 배열의 1번째 원소는 상태의 값을 변경할 때 사용하는 함수

APP 컴포넌트가 다시 실행되면서 setMode로 바뀐 값이 들어간다.

바뀌는 상태에 따라 UI 보여주기

클릭하는 목차에 따라 아래의 Content 내용이 바뀌어야 한다.

1. Nav 태그에서 클릭한 내용에 따라 id 값이 바뀌도록 한다.

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

이때, _id의 값은

props.onChangeMode(Number(e.target.id));

e.target.id로 현재 이벤트 태그의 id 값을 가져온다.
id의 경우, string값이므로 숫자로 변환한다.

2. id 값이 바뀌었다면 topics 배열에서 해당되는 데이터를 가져와 화면에 보여준다.

const [id, setId] = useState(null); //초기값 null

...

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>
}

content가 해당되는 내용을 보여준다.

CRUD - Create

Create를 누르면 title과 body를 작성해서 화면에 보여지도록 만들어보자

1. App 컴포넌트에 Create 링크를 만들고 링크 클릭 시 Create 컴포넌트가 동작하도록 하자

<a href="/create" onClick={(e) => {
	e.preventDefault();
    setMode('CREATE');
}}>Create</a>

2. Create 컴포넌트 만들기

function Create(props) {
  return <article>
    <h2>Create</h2>
    <form onSubmit={(e) => {
      e.preventDefault();
      const title = e.target.title.value; //title의 value 값을 가져올 수 있다.
      const body = e.target.body.value;
      
      props.onCreate(title, body);
    }}>
      <p><input type='text' name='title' placeholder='title'></input></p>
      <p><textarea name='body' placeholder='body'></textarea></p>
      <p><input type='submit' value='Create' /></p>
    </form>
  </article>
}
  • 데이터를 입력받은 form을 만든다.
  • onSubmit() 함수의 경우
    submit 버튼 클릭 시, reload 막기 위한 preventDefault();
    title, body의 value 값을 가져와서 onCreate() 함수로 전달

3. Create 컴포넌트로부터 submit 정보를 받아서 사용자 정의 로직 실행

const [nextId, setNextId] = useState(4);
const [topics, setTopics] = useState([
    {id:1, title:'html', body:'html is ...'},
  	...
]);

...

else if(mode === 'CREATE') {
    content = <Create onCreate={(_title, _body) => {
      // topics 배열에 새로운 원소가 추가되어야 함
      const newTopic = {id:nextId, title:_title, body:_body};
      const newTopocs = [...topics];
      
      newTopocs.push(newTopic);
      setTopics(newTopocs);
      setMode('READ');
      setId(nextId);
      setNextId(nextId + 1);
    }}/>
}

상태를 다룰 때, 객체 혹은 배열일 경우

  • value의 타입이 string, number, bigint, boolean, undefined, symbol, null 일 경우
    const [value, setValue] = useState(PRIMITIVE);

  • value의 타입이 object, array 일 경우
    const [value, setValue] = useState(Object);

    newValue = {...value} or [...value]
    newValue 변경
    setValue(newValue)

    React는 setValue를 호출했을 때, original 데이터와 새로 들어온 데이터가 같은 데이터인지 확인하고 만약 같은 데이터라면 컴포넌트를 굳이 다시 렌더링하지 않는다.

CRUD - Update

Update를 누르면 title과 body를 수정할 수 있도록 만들어보자

1. App 컴포넌트에 Update 링크를 만들고 링크 클릭 시 Update 컴포넌트가 동작하도록 하자
이때, mode가 'READ'일 때만 Update 컴포넌트가 보이도록 하기 위해 else-if문 안에 contextControl라는 변수를 만들어 보여준다.

let contextControl = null; 
...

else if (mode === 'READ') {
    ...
    contextControl = <li><a href={"/update/" + _id} onClick={(e) => {
      e.preventDefault();
      setMode('UPDATE');
    }}>Update</a></li>;
  }

그리고 Update 클릭 시, mode가 'UPDATE'로 변해서 update 로직을 타게 된다.

2. Update 컴포넌트 만들기

function Update(props) {
  const [title, setTitle] = useState(props.title);
  const [body, setBody] = useState(props.body);

  return <article>
    <h2>Update</h2>
    <form onSubmit={(e) => {
      e.preventDefault();
      const title = e.target.title.value; //title의 value 값을 가져올 수 있다.
      const body = e.target.body.value;

      props.onUpdate(title, body);
    }}>
      <p><input type='text' name='title' placeholder='title' value={title} onChange={(e) => {
        console.log(e.target.value);
        setTitle(e.target.value);
      }}></input></p>
      <p><textarea name='body' placeholder='body' value={body} onChange={(e) => {
        setBody(e.target.value);
      }}></textarea></p>
      <p><input type='submit' value='Update' /></p>
    </form>
  </article>;
}

React에서 props라는 데이터는 사용자가 그 컴포넌트로 전달한 일종의 명령이다. 따라서 props의 값을 바꾸려면 state로 바꾸어야 한다.
위 코드에서는 const [title, setTitle] = useState(props.title);const [body, setBody] = useState(props.body);로 바꾸어 주었다.

state는 컴포넌트 내부에서 변경가능한 데이터이다.
따라서 onChange() 함수에서 키보드를 입력할 때마다 새로운 value로 바뀌고 컴포넌트가 새로 렌더링된다.
위 코드에서는 onChange={(e) => { console.log(e.target.value); setTitle(e.target.value);onChange={(e) => { setBody(e.target.value); }}로 작성해주었다.

3. Update 컴포넌트로부터 submit 정보를 받아서 사용자 정의 로직 실행

const [id, setId] = useState(null);
const [topics, setTopics] = useState([
    {id:1, title:'html', body:'html is ...'},
  	...
]);

...

else if (mode === 'UPDATE') {
    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 = <Update title={title} body={body} onUpdate={(_title, _body) => {
      const newTopics = [...topics];
      const updatedTopic = {id:id, title:_title, body:_body};
      
      for(let i=0; i<newTopics.length; i++) {
        if(newTopics[i].id === id) {
          newTopics[i] = updatedTopic;
          break;
        }
      }
      setTopics(newTopics);
    }}/>
}

update의 경우, 원래 작성되어 있던 title, body의 값들을 보여줘야 하기 때문에 Update 컴포넌트의 props로 전달해주었다.

CRUD - Delete

Delete 버튼을 누르면 해당 topic을 삭제하도록 구현해보자

1. Delete 버튼 구현하고 삭제 로직 작성하기

contextControl = <>
      <li><a href={"/update/" + id} onClick={(e) => {
        e.preventDefault();
        setMode('UPDATE');
      }}>Update</a></li>

      <li><input type="button" value="Delete" onClick={() => {
        const newTopics = [];
        for(let i=0; i<topics.length; i++) {
          if (id !== topics[i].id) {
            newTopics.push(topics[i]);
          }
        }
        setTopics(newTopics);
        setMode('WELCOME');
	}}/></li>
</>;
  • React에서는 태그를 다룰 때, 하나의 태그 안에 있어야 한다. 따라서 빈태그의 경우, <> </> 의 경우 복수의 태그를 그룹핑하는 용도이다.
  • topics 배열을 돌면서 현재 topic의 id 값과 다르면 newTopics 배열에 넣어준다. 그리고 setTopics(newTopics); 해주면 삭제된 상태가 업데이트 된다.
  • topic을 삭제하면 그 아래 보여지는 세부사항도 안 보여야 하기 때문에 mode를 'WELCOME'으로 바꾸어 삭제 후, welcome 관련 내용이 보이도록 한다.

0개의 댓글