사용된 HTML

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script defer src="main.js"></script>
    <link rel="stylesheet" href="main.css" />
    <title>JS practice</title>
  </head>
  <body>
    <div class="btns">
      <button id="id_button">ID</button>
      <button class="class-button">CLASS</button>
      <button class="class-button">CLASS2</button>
      <button class="class-button">CLASS3</button>
    </div>
  </body>
</html>

1. element.children

선택된 요소의 자식요소 지정

리턴값이 HTMLCollection 배열이라 index를 통해서 접근이 가능하다.

const btns = document.querySelector(".btns");

console.log(btns.children); //HTML Collection
console.log(btns.children[1]); //자식요소중 두번째 ID
console.log(btns.children[2]); //자식요소중 세번째 CLASS

 

2. element. firstElementChild

선택된 요소의 첫 번째 자식요소 지정

3. element.lastElementChild

선택된 요소의 마지막 자식요소 지정

const btns = document.querySelector(".btns");

console.log(btns.firstElementChild); //첫번째 자식요소 ID
console.log(btns.lastElementChild); // 마지막 자식요소 CLASS3

 

4. element.parentElement

선택된 요소의 부모요소 지정

const btns = document.querySelector(".btns");

console.log(btns.parentElement); //부모 요소 지정 body

 

5. element previousElementSibling

선택된 요소의 형제요소 중 앞에 있는 요소

6.element.nextElementSibiling

선택된 요소의 형제요소 중 뒤에 있는 요소

const btns = document.querySelector(".btns");

console.log(btns.previousElementSibling); // null
console.log(btns.nextElementSibling); // script
const btns = document.querySelector(".btns");

console.log(btns.children);
console.log(btns.lastElementChild);
console.log(btns.firstElementChild);
console.log(btns.parentElement);
console.log(btns.previousElementSibling);
console.log(btns.nextElementSibling);

총 출력값

주요 요소 노드 프로퍼티

1. element.InnerHTML

요소 내부의 HTML 코드를 문자열로 리턴

HTML자체를 변경할 때 주로 사용된다.

const helloBtnById = document.getElementById("id_button");

helloBtnById.innerHTML = "<button>NEWID</button>";

출력값:

2. element.outerHTML

요소 노드 자체의 전체적인 HTML 코드를 문자열로 리턴

새로운 값을 할당하면 요소 자체가 바뀐다.

const helloBtnById = document.getElementById("id_button");

helloBtnById.outerHTML = "<div>NEWID</div>";

출력값:

 

3. element.textContent

HTML을 제외한 텍스트만을 리턴한다.

텍스트만 다루기 때문에 HTML을 바꿀수는 없다.

const helloBtnById = document.getElementById("id_button");

helloBtnById.textContent = "<div>NEWID</div>";

출력값:

새로운 요소 노드 다루기

자바스크립트에서 요소 노드를 새롭게 추가/수정/이동/삭제를 할 수 있다.

새로운 요소 만들기: document.createElement("태그이름")

요소 수정하기: element.textcontent, element.innerHTML, element.outerHTML

요소를 이동 혹은 추가하기:

1. parentElement.prepend(newElement) 자식 노드의 맨 앞에 추가

2. parentElement.append(newElement) 자식 노드의 맨 뒤에 추가

3. element.before(newElement) 요소의 앞에 추가

4. element.after(newElement) 요소의 뒤에 추가

요소 삭제하기: element.remove();

 

요소에 속성 추가하기: element.setAttribute("속성이름", "값")

요소의 속성 가져오기: element.getAttribute("속성이름");

요소의 속성 삭제하기: element.removeAttribute("속성이름");

 

class 이름 바꾸기: element.className = "바꿀값"

classList로 값 추가/삭제:

1. element.classList.add("추가할 값")

2. element.classList.remove("삭제할 값")

 

요소 추가하기 예시

const btns = document.querySelector(".btns");

const newButton = document.createElement("button");
newButton.textContent = "newbutton";
newButton.setAttribute("class", "class-button");

btns.append(newButton);

출력값:

 

 

사용된 HTML

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script defer src="main.js"></script>
    <link rel="stylesheet" href="main.css" />
    <title>JS practice</title>
  </head>
  <body>
    <button id="id_button">ID</button>
    <button class="class-button">CLASS</button>
    <button class="class-button">CLASS2</button>
    <button class="class-button">CLASS3</button>
  </body>
</html>

1. id 속성 이용하기

id에 해당하는 태그 하나만 지정함

사용법: document.getElementById(아이디이름: string): return HTML

const helloBtnById = document.getElementById("id_button");
console.log(helloBtnById); //HTML의 id태그 출력

출력값

잘 보이도록 CSS도 추가했습니다. 

 

2. class 속성 이용하기

같은 이름의 class 속성이 포함된 모든 값

사용법: document.getElementByClassName(클래스이름:string) : class에 해당하는 태그 모음(HTMLCollection)

const helloButton = document.getElementsByClassName("class-button");

console.log(helloButton);

출력값

3. HTML태그 이름으로 가져오기

사실상 자주 이용 되지 않는다.

사용법: document.getElementByTagName(태그이름: string): tag에 해당하는 태그 모음(HTMLCollection)

 

4.css선택자로 태그 선택하기

//main.css
#id_button {
  color: red;
}

button.class-button {
  color: blue;
}

4.1 하나만 선택하기

사용법: document.querySelector(css: string):css선택자 해당하는 태그 중 가장 첫 번째 태그 하나

4.2 모두 선택하기

사용법: document.querySelector(css: string):css선택자에 해당하는 태그 모음(NodeList)

const helloButton2 = document.querySelector(".class-button");
const helloButtons = document.querySelectorAll(".class-button");

console.log(helloButton2);
console.log(helloButtons);

출력값:

마무리

const helloBtnById = document.getElementById("id_button");
const helloButton = document.getElementsByClassName("class-button");
const helloButton2 = document.querySelector(".class-button");
const helloButtons = document.querySelectorAll(".class-button");

console.log(helloBtnById);
console.log(helloButton);
console.log(helloButton2);
console.log(helloButtons);

자바스크립트에서 HTML의 속성을 이용해서 태그에 접근하는 방법을 알아보았다. 이전에 했던것이지만 리액트를 쓰고 난 후 많이 까먹은 것 같아 다시 적어본다.

'JS' 카테고리의 다른 글

[JS] 이벤트 처리하기  (0) 2023.04.21
[JS] 요소 다루기 정리  (0) 2023.04.21
[JS]모듈(Module) 모듈화(Modularization)/ Import/Export  (0) 2023.04.06
[JS] 다양한 배열 메소드  (0) 2023.04.06
[JS] 에러 객체와 try catch문  (0) 2023.04.05

키값을 부여하지 않는다면 아래와 같은 코드가 콘솔에 출력된다.

의미를 조금 해석해 보자면 PokemonList의 key값이 정해지지 않아서 오류가 발생할 수 있다고 한다. 하지만 화면 렌더링은 정상적으로 이루어지고 있다. 그러면 무슨 문제가 있기에 리액트는 이것을 경고하는 것일까?

 

리액트 공식 문서에 따르면

"배열을 렌더링할 때 key값이 고유하지 않으면 렌더링이 잘못될 수 있다"로 결론을 내릴 수 있다.

 

key값을 만들때 주의점

  • 리스트를 만들 때 포함되어야 하는 특수한 문자열 속성이다. 
  • key값은 어떤 고유한 항목을 변경, 삭제, 추가 혹은 식별할지에 도움을 주는 프롭입니다.
  • key값은 배열 내부의 엘리먼트로 고유성을 부여해야 합니다.
  • key값은 배열의 index 값으로 사용하면 안 됩니다.

일단 이 정도로 정리할 수 있다. 즉 key값은 어떤 element의 변동이 일어났는지를 식별할 수 있게 도와주는 프롭인 것이다.

 

보통 배열을 화면에 렌더링 할 때 추가 삭제 등의 행동은 빈번하게 일어날 수 있다.

이때 key값이 없다면 다음 문제가 발생할 것이다.

  1. 요소의 값이 변경되었는지 삭제되었는지 불분명함
  2. React가 state가 변경되지 않았다고 판정하고 렌더링을 안 해줌

첫 번째부터 살펴보자면, 예를 들어 우리가 [index0 사과, index1 바나나, index2 자몽]이라는 배열을 렌더링 한다고 생각해 보자. 고유한 key값이 없어 index값을 key값으로 설정했다.

 

이제 바나나를 삭제하려고 한다.

그럼 결괏값은 [0 사과, 1 자몽]이 된다.

 

이번엔 자몽을 제거하고 바나나를 자몽으로 교체하려고 한다.

그럼 결괏값은 [0 사과, 1 자몽]이 된다.

 

그럼 두 가지 경우의 결괏값은 같아지는데 key값(index)을 비교해도 결과만 봐서는 어떻게 바뀌었는지 알 수 없다.

 

만약 [1: 사과, 2: 바나나, 3: 자몽]의 id값을 key로 지정한다고 가정하고 바나나를 삭제해 보면 [1: 사과, 3: 자몽]으로 결과만으로 어떤 과정이 있었는지 한눈에 보이는 것을 알 수 있다.

 

두 번째 경우는 VirtualDOM(가상돔 VDOM이라고도 한다) 이란걸 알아야 한다.

리액트나 다른 라이브러리에서 VirtualDOM을 보통은 사용한다고 들었다.

필자는 리액트에 대한 공부 밖에 아직 하지 않아서 잘 모른다

 

일단 내가 공부한 선에서 얘기를 해보자면, 브라우저는 렌더링을 할 때 DOM을 사용하게 되는데,

리액트의 VirtualDOM은 리액트의 컴포넌트가 변화할 때 이를 감지하고 저장해서 변화가 일어난 VirtualDOM과 RealDOM을 비교해서 새로운 DOM을 새로 생성하고 VirtualDOM을 업데이트한다.

근데 이때 사용되는 리스트의 비교값이 key값이다.

 

그럼 생각해 보자. 만약 index를 키값으로 설정하고 [0: 사과, 1: 바나나, 2: 자몽]이런 배열에서 바나나멜론으로 교체했다. [0:사과, 1:멜론, 2: 자몽] 여기서 key값이 바뀌었는가? index값은 그대 로고 안의 내용만 바뀌었기 때문에 리액트는 이를 변경되지 않았다고 판정하고 리렌더링을 해주지 않는다

 

 

마무리

key값은 고유한 값을 지정해 주어야 한다.

key값이 없으면 리렌더링 할 때 오류가 발생할 수 있다.

 

Reference

React에서 키의 역할 - 네이버 블로그 (리액트 내부의 컴포넌트 생성에 대해서도 추가로 다루고 있다.)

https://junior-datalist.tistory.com/184 - 리액트에서 키값이 필요한 이유

'React' 카테고리의 다른 글

[React] JSON 배열 렌더링하기  (2) 2023.04.18
[React] Props 정리  (0) 2023.04.17
[React] CSS 사용하기  (0) 2023.04.12
[React] JSX 문법  (0) 2023.04.08
[React] 개발자 도구 설치  (0) 2023.04.08

아래 JSON 데이터 배열을 랜더링 해보려고 한다.

[
  {
    "id": 1,
    "name": "이상해씨",
    "types": [
      "풀",
      "독"
    ]
  },
  {
    "id": 2,
    "name": "이상해풀",
    "types": [
      "풀",
      "독"
    ]
  },
...
//기본 index.js 코드
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.js";
import items from "./pokemons.json";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <>
    <App items={items} />
  </>
);

map메서드 이용하기

배열 메소드 map에서 콜백함수의 리턴 값을 리액트 엘리먼트로 리턴한다.

//Pokemon.js
function Pokemon({ item }) { // PokemonList에서 추출한 item 값을 이용한다.
  return (
    <div>
      No.{item.id} {item.name}
    </div>
  );
}

function PokemonList({ items }) { // App.js에서 items prop을 받아온다.
  return (
    <ul>
      {items.map((item) => { //map 메소드를 이용해 새로운 배열을 만든다
        return (
          <li key={item.id}>
            <Pokemon item={item} />
          </li>
        );
      })}
    </ul>
  );
}

export default PokemonList;
//App.js
import PokemonList from "./Pokemon";
import items from "./pokemons.json"; //json파일 불러오기

function App() {
  return <PokemonList items={items} />; 
}

export default App;

Sort로 정렬하기

아이디가 양수일 경우에는 오름차순

아이디가 음수일 경우에는 내림차순

Pokemon.js는 위와 동일

//App.js
import { useState } from "react";
import PokemonList from "./Pokemon";
import items from "./pokemons.json";

function App() {
  const [direction, setDirection] = useState(1);

  //onClick속성에 들어갈 값들
  const handleAscClick = () => setDirection(1); //추가된 함수 => 양수일경우 오름차순
  const handleDesClick = () => setDirection(-1); //추가된 함수 => 음수일경우 내림차순

  //id값을 기준으로 정렬
  const sortedItems = items.sort((a, b) => direction * (a.id - b.id)); // 추가된 sort

  return (
    <div>
      <div>
        <button onClick={handleAscClick}>번호 순서대로</button> //button으로 확인
        <button onClick={handleDesClick}>번호 반대로</button> //button으로 확인
      </div>
      <PokemonList items={sortedItems} /> //items에서 sortedItems로 변경
    </div>
  );
}

export default App;

filter함수로 삭제하기

filter함수를 이용해 클릭한 item id값과 현재 id값중 다른값을 리턴하여 새로운 배열을 만든다.

//Pokemon.js
function Pokemon({ item, onDelete }) { // 삭제 프롭 추가 PokemonList로 부터 받아옴
  const handleDeleteClick = () => onDelete(item.id); // 삭제 함수 추가

  return (
    <div>
      No.{item.id} {item.name}
      <button onClick={handleDeleteClick}>삭제</button> //삭제 버튼 추가
    </div>
  );
}

function PokemonList({ items, onDelete }) { //삭제 프롭 추가 App.js로 부터 받아옴
  return (
    <ul>
      {items.map((item) => {
        return (
          <li key={item.id}>
            <Pokemon item={item} onDelete={onDelete} /> //삭제 프롭 추가
          </li>
        );
      })}
    </ul>
  );
}

export default PokemonList;

 

//App.js
import { useState } from "react";
import PokemonList from "./Pokemon";

//Items => mockItems로 변경
import mockItems from "./pokemons.json";

function App() {
  const [direction, setDirection] = useState(1);
  
  //items 선언 => 초깃값은 똑같아서 items 그대로 쓰면됨
  const [items, setItems] = useState(mockItems);

  //onClick속성에 들어갈 값들
  const handleAscClick = () => setDirection(1); //양수일경우 오름차순
  const handleDesClick = () => setDirection(-1); //음수일경우 내림차순

  //id값을 기준으로 정렬
  const sortedItems = items.sort((a, b) => direction * (a.id - b.id));

  //추가된 함수 => 클릭한 item의 아이디값과 다른값을 모두 출력
  const handleDelete = (id) => setItems(items.filter((item) => item.id !== id));
 

  return (
    <div>
      <div>
        <button onClick={handleAscClick}>번호 순서대로</button>
        <button onClick={handleDesClick}>번호 반대로</button>
      </div>
      <PokemonList items={sortedItems} onDelete={handleDelete} /> // onDelete 프롭 추가
    </div>
  );
}

export default App;

렌더링 값:

마무리

CSS는 사용하지 않아서 출력값을 보기가 좀 어렵긴 하지만 읽고 정렬하고 삭제하는 기능은 정상적으로 작동하는 것을 확인할 수 있었다. 위에서 사용된 메소드들이 생소하다면 링크를 타고 배열의 메소드를 확인해보는것을 추천한다.

 

Reference

https://www.codeit.kr/learn/5035 - codeit 배열렌더링하기

'React' 카테고리의 다른 글

[React] 배열의 key값이 중요한 이유  (0) 2023.04.18
[React] Props 정리  (0) 2023.04.17
[React] CSS 사용하기  (0) 2023.04.12
[React] JSX 문법  (0) 2023.04.08
[React] 개발자 도구 설치  (0) 2023.04.08

컴포넌트에 파라미터를 전달할 때 HTML에서의 속성값을 쓰는 것처럼 전달한다. 이때 이 컴포넌트에 지정한 속성을 리액트에서 Props(프롭)라고 부른다. Props는 properties(속성)의 약자다.

컴포넌트에 속성을 지정하면 각 속성이 하나의 객체로 모여서 컴포넌트를 정의한 함수의 첫 번째 파라미터로 전달된다.

쉽게 생각하면 컴포넌트의 prop들은 하나의 객체 안에 들어가는대 이때 prop의 이름은 객체의 key가 되고 속성의 값은 key에 할당된 값이 된다.

//App.js
import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <Hello name="react" /> //name이 prop이다.
  );
}

export default App;
//Hello.js
import React from 'react';

function Hello(props) { //console에 props를 출력하면 객체가 출력된다.
  return <div>안녕하세요 {props.name}</div> //객체 값에 접근하는것과같이 key를 이용해 접근한다.
}

export default Hello;

위 코드를 보자면 name이 props의 키값이 되고 react가 props name의 키값이 된다.

let props = { // props객체 표현
 name: "react"
}

구조분해 문법과 같이 사용하면 좀더 간결하게 코드를 작성할 수 있다.

//Hello.js
import React from 'react';

function Hello({name}) { //name값을 구조분해
  return <div>안녕하세요 {name}</div> //name 변수로 바로 사용가능
}

export default Hello;

한 가지 특별한 prop이 존재하는데 바로 children 프롭이다. 보통 컴포넌트는 <컴포넌트 /> 이런식으로 작성한다 그런데 버튼 같은 태그를 사용할 때는 여는 태그(<button>)와 닫는 태그(</button>)의 형태로 작성할 때가 있다. 이 때 그 이 태그들 사이에 작성된 코드가 바로 이 children 값에 담기게 된다.

// App.js

import React from 'react';
import ChildComponent from './ChildComponent';

function App() {
  return (
    <div>
      <ChildComponent>Hello, world!</ChildComponent>
    </div>
  );
}

export default App;
// ChildComponent.js

import React from 'react';

function ChildComponent(props) {
  return (
    <div>
      {props.children}
    </div>
  );
}

export default ChildComponent;

Reference

https://www.codeit.kr/learn/4652 - codeit props 정리하기

https://react.vlpt.us/basic/05-props.html - props 정리한 블로그

'React' 카테고리의 다른 글

[React] 배열의 key값이 중요한 이유  (0) 2023.04.18
[React] JSON 배열 렌더링하기  (2) 2023.04.18
[React] CSS 사용하기  (0) 2023.04.12
[React] JSX 문법  (0) 2023.04.08
[React] 개발자 도구 설치  (0) 2023.04.08

+ Recent posts