반응형

 


async / await

 

비동기 함수인 fetch를 이용하면, json 파일을 읽을 수 있다.

입력 칸에 색을 입력한 후 버튼을 클릭하면, 

해당 색에 해당하는 헥사 코드를 json 데이터에서 찾아 화면에 나타내는 코드를 async/await로 작성

const inputElem = document.querySelector('#inputColor');
const buttonElem = document.querySelector('#buttonSubmit');
const hexaCodeElem = document.querySelector('#hexaCode');

async function getHexaCode(e) {
  // 새로고침 방지
  e.preventDefault();
  const userInputColor = inputElem.value;

  // await를 반드시 fetch(), json() 앞에 붙여야 함
  const result = await fetch('data.json');
  const datas = await result.json();

  // 배열의 요소 중, color 가, 사용자가 입력한 색과 일치하는 요소를 찾음.
  const findData = datas.find(data => data.color === userInputColor);

  // 찾은 요소는 객체인데, 그 value값이 헥사코드임.
  hexaCodeElem.innerHTML = findData.value;
  
  // 참고로, 아래 코드를 추가하면 색상도 반영됨 (채점과는 무관합니다).
  hexaCodeElem.style.color = findData.value;
}

buttonElem.addEventListener('click', getHexaCode);

 

 

 


Fetch API 사용하기

fetch() 이용하며 헤더를 반드시 명시한다.

body에 JSON.stringify()를 사용해서 유저 정보(“첫번째 참가자”)라는 name을 서버에 업데이트

fetch('https://reqres.in/api/users', {
  method: 'POST',
  headers: { 'Content-type': 'application/json' },
  body: JSON.stringify({
    name: '첫번째 참가자',
  }),
})

 

response.ok 는 HTTP Status code가 200-299 사이면 true, 그외는 false

만약 res.ok일 경우 “Success!” 라는 메시지와 함께 res.json()을 반환하고,

ok가 아닐 경우, “failed”라는 메시지를 콘솔에 띄운다.

//fetch()의 인자로 'https://reqres.in/api/users' 라는 가짜 사용자 정보 API url을 패스.
fetch('https://reqres.in/api/users', {
  method: 'POST',
  //3. 헤더를 반드시 명시합니다.
  headers: { 'Content-type': 'application/json' },
  //4.body에 `JSON.stringify()`를 사용해서 유저 정보(Object)를 서버에 업데이트.
  body: JSON.stringify({
    name: '첫번째 참가자',
  }),
})
  .then(res => {
    // response.ok는 HTTP Status code가 200-299 사이면 true, 그외는 False.
    // 만약 res.ok일 경우 "Success!" 라는 메시지와 함께 `res.json()`을 반환하고,
    if (res.ok) {
      console.log('success!');
      return res.json();
    }
    // ok가 아닐 경우, "failed"라는 메시지를 콘솔에 띄운다.
    else {
      console.log('failed');
    }
  })
  .then(data => console.log(data))
  .catch(error => console.log('Error'));

 

 

 


await 이미지 띄우기

1. 구글에서 이미지 주소를 가져와 fetch인자로 불러온다.

import 'babel-polyfill';

async function fetchImage() {
  // fetch() 메서드를 호출하여 구글에 검색된 이미지를 가져오고 변수(response)에 저장. 
  // 이때 await을 사용
  
  let response = await fetch(
    'https://pbs.twimg.com/profile_images/799445590614495232/ii6eBROd_400x400.jpg'
  );

  const error = false;

  if (!response.ok || error) {
    throw new Error(`HTTP error! status: ${response.status}`);
  } else {
    document.write("here's the image");
    return await response.blob();
  }
}

2. then()블록을 사용하여 promise가 성공적인 실행에 응답하며 catch()로 에러가 발생했을때 대처하는 코드를 작성

// then() 블록을 사용하여 promise가 성공적인 실행에 응답하고 에러가 발생했을때 catch를 하는 코드를 작성하세요.

fetchImage()
  //then()의 인자로 blob을 받는다.
  .then(blob => {
    //실행코드
    // 이미지를 변환해서 <img>의 src를 객체 URL로 설정하여 이미지에 html에 표시되도록 한다.

    // Blob 객체를 가리키는 객체 URL을 생성
    let objectURL = URL.createObjectURL(blob);

    // blob(이미지)을 표시할 <img> 요소를 만든다.
    let image = document.createElement('img');

    // <img>의 src를 객체 URL로 설정하여 이미지에 표시되도록 한다.
    image.src = objectURL;

    // ADOM에 <img> 요소 추가
    document.body.appendChild(image);
  })
  .catch(error => console.log(error));

반응형
반응형

 


Promise

 

Promise

자바스크립트에서 비동기 함수를 다루는 방법

 

Promise 생성문법

var myPromise1 = new Promise(function(resolve, reject) {
  resolve(1);
});

myPromise1.then();  //이행

 

Promise의 resolve(이행)와 reject(거부)

Promise라는 object를 갖고 then이란 콜백 함수를 요청하면 사용자 데이터를 등록한 대로 콜백 함수를 불러줄 수 있다.

var myPromise2 = new Promise(function(resolve, reject) {
  reject(1);		
});

myPromise2.then();	// 거부

 

 

예제1

getData()함수에 new Promise()를 호출할 때 콜백 함수의 인자를 resolve, reject로 선언.

이때, resolve를 실행해서 아래 선언된 메시지를 resolve 인자값으로 넘기기.

// new Promise()를 호출할 때 콜백 함수의 인자를 resolve, reject로 선언.
function getData() {
  return new Promise(function (resolve, reject) {
    //resolve를 실행해서 아래 선언된 메시지(data)를 resolve 인자 값으로 넘김.
    var data = 'javascript promise';
    resolve(data);
  });
}

// then을 이용해서 resolve()의 결과 값 data를 resolvedData로 받기.
getData().then(function (resolvedData) {
  document.write(resolvedData);
});

 

 

예제2

 

getPosts() 함수 작성 

posts 의 내용을 불러와 index.html에 표시하는 코드

//posts 변수
const posts = [
  { title: 'Post 1', body: '첫번째 게시글입니다.' },
  { title: 'Post 2', body: '두번째 게시글입니다.' },
  { title: 'Post 3', body: '세번째 게시글입니다.' },
  { title: 'Post 4', body: '네번째 게시글입니다.' },
  { title: 'Post 5', body: '다섯번째 게시글입니다.' },
];

function getPosts() {
  //setTimeout()를 사용해서 1초 후에 posts element를 rendering 합니다.
  setTimeout(() => {
    let output = '';
    //위에 정의된 posts 내의 게시글 제목과 내용을 forEach()을 사용해서 rendering 합니다.
    posts.forEach(post => {
      output = output + `<li>${post.title}<br> 내용: ${post.body} </li>`;
    });
    //rendering 된 게시글을 document.body.innerHTML을 사용해서 html에 띄어줍니다.
    document.body.innerHTML = output;
  }, 1000);
}

 

createPost() 함수 작성

이행 상태가 되면 then()을 이용하여 처리 결과 값을 받을 수 있다.

실패 상태가 되면 실패한 이유(실패 처리의 결과 값)를 catch()로 받을 수 있다.

function createPost(post) {
  //Promise를 생성해서 resolve와 reject를 인자로 받습니다.
  return new Promise(function (resolve, reject) {
    //Promise 내에 setTimeout으로 비동기 처리하는데,
    setTimeout(() => {
      // createPost()함수에 인자로 받아온 post를 push할 때
      posts.push(post);
      const error = false;
      // 에러없이 성공적으로 호출되면(if(!error)) `resolve`를 실행
      if (!error) resolve();
      // 그렇지 않으면 에러를 받아들이는 `reject`를 2초 후에 실행
      else reject('error: wrong');
    }, 2000);
  });
}

createPost({ title: 'Post N', body: 'N번째 게시글입니다.' })
  .then(getPosts)
  .catch(err => console.log(err));

 

 

 


fetch 이용해 json데이터 가져오기

 

 

비동기 함수인 fetch를 이용하면, json 파일을 읽을 수 있다.

function showHexaCode(e) { 
  // 새로고침 방지
  e.preventDefault()
  
  const userInputColor = inputElem.value 
  
  // fetch -> response.json() 하는 과정은 고정입니다 (번거롭지만, 매번 해 주어야 함).
  // 물론 response 대신 res 등으로 변수명은 바꾸어도 됩니다.
  fetch('data.json')
    .then(response => response.json())
    .then(datas => {
      // 배열의 요소 중, color 가, 사용자가 입력한 색과 일치하는 요소를 찾음. 
      const foundData = datas.find(data => data.color === userInputColor)
      
      // 찾은 요소는 객체인데, 그 value값이 헥사코드임.
      hexaCodeElem.innerHTML = foundData.value
      
      // 참고로, 아래 코드를 추가하면 색상도 반영됨.
      hexaCodeElem.style.color = foundData.value
    })
  
}

const inputElem = document.querySelector('#inputColor')
const buttonElem = document.querySelector('#buttonSubmit')
const hexaCodeElem = document.querySelector('#hexaCode')

buttonElem.addEventListener("click", showHexaCode)

 

반응형
반응형

동기 처리 / 비동기 처리

동기처리 함수를 그대로 수행

// 동기처리 함수를 그대로 수행하는 `printImmediately()` 함수
function printImmediately(print) {
  print();
}

//동기처리
printImmediately(() => console.log('hello'));

 

특정 시간 이후에 비동기처리 콜백을 보내는 함수

//비동기 처리 Asynchronous callback
function printWithDelay(print, timeout) {
  // setTimeout을 이용해서 비동기 처리 함수를 완성
  setTimeout(() => {
    print();
  }, timeout);
}

// printWithDelay()를 실행해서 3초 늦게 "async callback" 문장을 띄우는 코드
printWithDelay(() => console.log('async callback'), 3000);

 


setTimeout 사용하는 함수

 

함수 실행 시, 3 -> 2-> 1-> “끝” 이 차례대로 출력(console.log)됨.

  • 3은 함수 실행 시 딜레이 없이 바로 출력되어야 합니다.
  • 2는 3이 출력된 1초 후 출력되어야 합니다.
  • 1은 2가 출력된 1초 후 출력되어야 합니다.
  • “끝”은 1이 출력된 1초 후 출력되어야 합니다.
  • 3,2,1은 숫자가 출력되어야 합니다. (문자열 아님)
function countDownThree() {
  console.log(3);
  setTimeout(() => console.log(2), 1000);
  setTimeout(() => console.log(1), 2000);
  setTimeout(() => console.log('끝'), 3000);
}

 

 

 


setTimeout 으로 디바운싱 구현하기

 

변화하는 도중(1초 이내에 다른 변화가 생김)에는 효과가 발생 안 하다가, 

멈출 시(1초 이상 변화가 없음) 효과가 발생하는 것을 디바운싱(debouncing) 이라고 한다.

 

// input 엘리먼트 가져옴
const nameElem = document.querySelector('#inputName')

let alertTimer
function alertWhenTypingStops() {
  // 앞선 타이머를 리셋
  if (alertTimer) {
    clearTimeout(alertTimer)
  }
  
  const name = nameElem.value
  // 타이머 시작
  alertTimer = setTimeout(() => alert(`입력된 이름: ${name}`), 1000)
}

// input 이벤트는 사용자가 값을 수정할 때마다 발생
nameElem.addEventListener("input", alertWhenTypingStops)

 

 


setTimeout 으로 쓰로틀링 구현하기

 

조건이 지속적으로 만족될 때에는 효과(점수 증가, api 요청 등)가 주기적으로 발생하다가,

멈출 시(조건 불만족) 효과가 멈추는 것을 쓰로틀링(throttling) 이라고 한다.

 

쓰로틀링은 코드 자체는 길지 않지만, 한 번에 이해하기는 어려울 수 있다.

코드를 보면서, 언제 true고 false인지, 타이머가 언제 생겨나고 끝나는지가 중요하다.

 

// 자유롭게 코드를 작성하여, 예시 화면이 구현되도록 해 보세요.

// input 엘리먼트 가져옴
const nameElem = document.querySelector('#inputName')


let isInThrottle
function increaseScoreDuringTyping() {
  if (isInThrottle) {
    return
  }
  
  isInThrottle = true
  
  // 타이머 세팅
  setTimeout(() => {
    const score = document.querySelector('#score')
    const newScore = parseInt(score.innerText) + 1
    score.innerText = newScore
    
    isInThrottle = false
  }, 500)
}

// input 이벤트는 사용자가 값을 수정할 때마다 발생
nameElem.addEventListener("input", increaseScoreDuringTyping)
반응형
반응형

Form 개발

 

React를 이용해 사용자로부터 데이터를 입력받아 처리하기 위한 관문인 Form

이번 실습에서는 State와 이벤트를 활용해 개발을 진행

 

구현할 Form의 형태

  1. 컴포넌트 형태로 개발
  2. Form 컴포넌트 내부에서 State를 이용해 사용자의 입력을 저장/관리
  3. Form Submit 이벤트가 발생되면 부모 컴포넌트로 그 데이터를 전달
import React, { useState, useCallback } from "react";

const InsertForm = ({ onInsert }) => {
    const [inputValue, setInputValue] = useState("");
    
    const handleSubmit = useCallback((event) => {
        // 기본적인 HTML 동작으로 인해 페이지가 새로고침 되는 것을 방지
        event.preventDefault(); 
        // props로 넘어온 onInsert가 정상적인 함수인 지 확인하여 에러 방지
        if(typeof onInsert === "function" && inputValue) { 
            onInsert(inputValue);
        }
        // state 초기화
        setInputValue("");
    },[onInsert, inputValue])

    return (
        <form onSubmit={handleSubmit}>
            <input value={inputValue} onChange={(event) => {
                setInputValue(event.target.value);
            }} />
            <button type="submit">등록</button>
        </form>
    )

}

export default InsertForm;

 

 


List 표현

 

Form으로부터 전달받은 값들을 리스트에 저장 후, 리스트의 값을 Array 메소드 이용하여 순차적으로 화면에 출력

 

구현할 List의 형태

  1. Form으로부터 전달받은 값을 todoList array에 push하는 로직
//src/App.js


import React, { useState } from 'react';
import InsertForm from "./components/InsertForm";
import ListView from "./components/ListView";

function App() {
  const [todoList, setTodoList] = useState([]);
  
  const handleInsert = (value) => {
    setTodoList((current) => {
      const newList = [...current];
      newList.push({
        key: new Date().getTime(), // JSX에서 Array의 값을 표현할 때 각 요소를 구분하기 위한 값
        value: value, // onInsert로부터 전달받은 값,
        isCompleted: false, // 완료 처리를 위한 flag
      });
      return newList;
    })
  }
  
  const handleComplete = (index) => {
    setTodoList((current) => {
      const newList = [...current];
      newList[index].isCompleted = true;
      return newList;
    })
  }
  
  const handleRemove = (index) => {
    setTodoList((current) => {
      const newList = [...current];
      newList.splice(index, 1);
      return newList;
    })
  }
  
  return (
    <div className="App">
        <ListView todoList={todoList} onComplete={handleComplete} onRemove={handleRemove} />
        <InsertForm onInsert={handleInsert} />
    </div>
  );
}

export default App;
  1. todoList와 핸들링함수를 props로 전달받아 화면에 출력하는 ListView 컴포넌트
// src/component/ListView.js


import React from "react";

const ListView = ({todoList, onComplete, onRemove}) => {
  return (
    <div>
      <ol>
        {todoList.map((item, index) => {
          return (
            <li key={item.key}>
              <span>{item.value}</span>
              <button type="button" onClick={() => {
                if(typeof onComplete === "function") {
                  onComplete(index);
                }
              }}>완료</button>
              <button type="button" onClick={() => {
                if(typeof onRemove === "function") {
                  onRemove(index);
                }
              }}>삭제</button>
            </li>
          );
        })}
      </ol>
    </div>
  )

}

export default ListView;

 

 


CSS 꾸미기

 

1. CSS 불러오기

별도의 CSS 파일을 작성 후 프로젝트에 적용하고 싶은 경우 import해서 스타일을 적용한다.

import "./App.css";

 

2. jsx 내에서 inline style로 적용하기

스타일은 반드시 object로 적는다. {{ }}

(jsx에서 자바스크립트 표현을 사용하겠다는 의미의 괄호 + object라는 의미의 괄호)

* 주의) Property name은 camel case로 적는다.

 

return (
    <form
      onSubmit={handleSubmit}
      style={{
        backgroundColor: '#ffffff',
        borderRadius: '16px',
        marginBottom: '16px',
        display: 'flex',
        justifyContent: 'space-between',
        alignItems: 'center',
      }}
    >
      <input
        value={inputValue}
        onChange={event => {
          setInputValue(event.target.value);
        }}
        style={{
          flex: 1,
          border: 'none',
          color: '#000000',
          padding: '6px, 12px',
          backgroundColor: 'transparent',
        }}
      />
      <button
        type="submit"
        style={{
          border: 'none',
          borderRadius: 16,
          backgroundColor: '#3ab6bc',
          color: '#ffffff',
          cursor: 'pointer',
          padding: '8px 16px',
        }}
      >
        등록
      </button>
    </form>
  );

jsx에서 스타일은 반드시 camel case로 선언해야 함!!

background-color 대신 backgroundColor
border-radius 대신 borderRadius

 

 


부가 기능 구현

 

  • 완료버튼 클릭시 이펙트(애니메이션) 추가하기
.listview ol li span {
    ...
    position: relative;
}
.listview ol li span::after {
   content: "";
   position: absolute;
   left: 0;
   top: 50%;
   transition: width 0.2s ease-in-out;
   width: 0%;
   height: 3px;
   background-color: #524FA1;
}
.listview ol li.completed span::after {
   width: 100%;
}

// 제거
.listview ol li.completed span

 

  • todolist 개수를 제한하기

list가 10개 이상이면 제한하는 기능

  const isLimitReached = useMemo(() => {
    return todoList.length >= 10;
  }, [todoList]);
  
  
  return (
    <div className="App">
      <ListView
        todoList={todoList}
        onComplete={handleComplete}
        onRemove={handleRemove}
      />

      {isLimitReached && (
        <div
          style={{
            padding: '8px 16px',
            border: '1px solid #FA466A',
            backgroundColor: '#feecf0',
            color: '#FA466A',
            marginBottom: 16,
          }}
        >
          ※ 할일 목록이 너무 많습니다.
        </div>
      )}
      <InsertForm onInsert={handleInsert} disabled={isLimitReached} />
    </div>
  );
반응형

'프론트엔드 > react.js' 카테고리의 다른 글

[React.js] Hooks  (0) 2022.11.21
[React.js] 이벤트 처리  (0) 2022.11.15
[React.js] State  (0) 2022.11.14
[React.js] Prop  (0) 2022.11.14
[React.js] JSX와 컴포넌트  (0) 2022.11.14
반응형

 

Hook 이란?

컴포넌트에서 데이터를 관리(State)하고, 데이터가 변경될 때 상호작용(Effect)을 하기 위해 사용된다.

State Hook과 Effect Hook이 있다.

 

Hook이 필요한 이유?

기존 컴포넌트 내에서 State와 생명주기를 관리하기 위해서 반드시 클래스 컴포넌트를 사용해야 했다.

클래스 컴포넌트를 보완하고 함수 컴포넌트에서 클래스 컴포넌트의 기능을 구현하기 위해 추가된 Hook

 

Hook 사용시 주의사항

Hook은 React함수(컴포넌트, Hook) 내에서만 사용이 가능하다.

Hook의 이름은 반드시 use로 시작해야 한다.

최상위 레벨에서만 Hook을 호출할 수 있다.

 

 

 

1. state hook

 

- useState는 컴포넌트 내 동적인 데이터를 관리할 수 있는 hook

- 최초에 useState가 호출될 때 초기값으로 설정되며 이후 재렌더링이 될 경우 무시된다.

- state는 읽기 전용이므로 직접 수정하지 않기

- state를 변경하기 위해서는 setState를 이용하거나 혹은 현재 값을 매개변수로 받는 함수를 전달

- state가 변경되면 자동으로 컴포넌트가 재 렌더링 된다.

 

 


 

 

2. effect hook

useEffect(EffectCallBack, Deps?)

effect hook을 사용하면 함수 컴포넌트에서 side effect를 수행할 수 있다

컴포넌트가 최초로 렌더링 될 때 지정한 State나 Prop가 변경될 때마다 이펙트 콜백 함수가 호출된다.

 

Effect Hook 사용 형태

const App = () => {
  useEffect(EffectCallback, Deps);
}

 

예제1) input 태그 안에 값이 변경될 때마다 effect callback 함수가 실행됨

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

function App() {
  const [inputValue, setInputValue] = useState('default');
  useEffect(() => {
    console.log(inputValue);
  }, [inputValue]);				//depth 있으면 변경될때마다 콜백함수가 실행됨
  return (
    <div className="App">
      <input
        value={inputValue}
        onChange={event => {
          setInputValue(event.target.value);
        }}
      />
    </div>
  );
}

export default App;

 

예제2) 컴포넌트가 생성되고 제거될때만 실행됨

컴포넌트가 생성됐을 때, 컴포넌트가 소멸될 때를 감지해서 특정 로직을 실행할 수 있다.

useEffect의 이펙트 함수 내에서 다른 함수를 리턴하는 경우 state가 변경되어 컴포넌트가 다시 렌더링되기 전과 컴포넌트가 없어질 때(destroy) 호출할 함수를 지정하게 된다.

 

버튼을 누르면 <Greeting/>이 생성되고 삭제된다.

<Greeting/> 내부 effect 함수는 depth가 [ ]이라 컴포넌트 생성, 소멸시에만 콜백함수가 실행되도록 한다.

Effect Callback 함수에서 반환하는 함수는 현 상태가 종료될 때 호출된다.

// src/components/Greeting.js

import React, { useEffect } from 'react';

const Greeting = () => {
  useEffect(() => {
    console.log('컴포넌트가 생성되었습니다.');		// <Greeting/>컴포넌트 생성시 실행
    return () => {
      console.log('컴포넌트가 소멸되었습니다.');		// <Greeting/>컴포넌트 소멸시 실행
    };
  }, []);
  return <h1>안녕하세요</h1>;
};

export default Greeting;
import React, { useState } from 'react';
import Greeting from './components/Greeting';

function App() {
  const [isCreated, setIsCreated] = useState(false);
  return (
    <div className="App">
      <button
        onClick={() => {
          setIsCreated(current => {
            console.log('!current', !current);
            return !current;
          });
        }}
      >
        컴포넌트 생성/제거
      </button>
      
      // isCreated가 true이면 <Greeting/> 생성, false이면 삭제
      {isCreated && <Greeting />}
    </div>
  );
}

export default App;

 

 


useMemo( ) 훅

지정한 State나 Props가 변경될 경우 해당값을 활용해 계산된 값을 메모이제이션하여 재렌더링 시 불필요한 연산 줄인다.

오래 걸리는 로직을 작성하지 않는 것을 권장한다.

import React, { useState, useMemo } from 'react';

function App() {
  const [foo, setFoo] = useState(0);
  const [bar, setBar] = useState(0);
  
  // foo, bar 두 값 중 하나라도 변경되면 useMemo에 정의한 함수가 실행된다.
  const multi = useMemo(() => {
    return foo * bar;
  }, [foo, bar]);

  return (
    <div className="App">
      <input
        value={foo}
        onChange={event => {
          setFoo(parseInt(event.target.value));
        }}
      ></input>
      <input
        value={bar}
        onChange={event => {
          setBar(parseInt(event.target.value));
        }}
      ></input>
      <div>{multi}</div>			// memo한 값 호출
    </div>
  );
}

export default App;

 

 

useCallback( ) 훅

함수를 메모이제이션 하기 위해 사용하는 Hook이다. 컴포넌트가 재렌더링 될 때 불필요하게 함수가 다시 생성되는 것을 방지한다. useMemo(()=> fn, deps) 와 useCallback(fn, deps)는 같은 기능을 수행한다.

import React, { useState, useCallback } from 'react';

function App() {
  const [foo, setFoo] = useState(0);
  const [bar, setBar] = useState(0);
  
	// useCallback 함수 이용해 메모이제이션 하는 Hook
  const calc = useCallback(() => {
    return foo + bar;
  }, [foo, bar]);

  return (
    <div className="App">
      <input
        value={foo}
        onChange={event => {
          setFoo(parseInt(event.target.value));
        }}
      />
      <input
        value={bar}
        onChange={event => {
          setBar(parseInt(event.target.value));
        }}
      />
      <div>{calc()}</div>		// 함수 형태로 호출
    </div>
  );
}

export default App;

 

useRef( ) 훅

컴포넌트 생애 주기 내에서 유지할 ref 객체를 반환한다.

ref 객체는 .current라는 프로퍼티를 가지며, 이 값을 자유롭게 변경할 수 있다.

일반적으로 React에서 DOM 엘레멘트에 접근할 때 사용한다.

useRef에 의해 반환된 ref객체가 변경되어도 컴포넌트가 재렌더링 되지 않는다.

import React, { useRef } from 'react';

function App() {
  const inputRef = useRef();

  return (
    <div className="App">
      <input ref={inputRef} />		// input의 ref를 useRef()로 선언함
      <button
        onClick={() => {
          alert(inputRef.current.value);		// 접근할 땐 current 놓치면 안됨
        }}
      >
        클릭
      </button>
    </div>
  );
}

export default App;

 


 

나만의 hook, custom hook

자신만의 hook을 만들면, 컴포넌트 로직을 함수로 뽑아내어 재사용할 수 있다.

UI 요소의 재상용성을 올리기 위해 컴포넌트를 만드는 것처럼, 로직의 재사용성을 높이기 위해서는 커스텀훅을 제작한다.

- 한 로직이 여러번 사용될 경우 함수를 분리하는 것처럼, Hook을 만드는것

- Hook 이름은 use로 시작해야 한다.

- 한 Hook내 State는 공유되지 않는다.

 

 

초기값으로 inOn state를 저장한 다음, toggle()함수가 호출되면 state를 반전하여 저장하는 훅

// src/hooks/useToggle.js

import { useState } from 'react';
const useToggle = initialValue => {
  const [isOn, setIsOn] = useState(initialValue);
  const toggle = () => {
    setIsOn(current => {
      return !current;
    });
  };
  return { isOn, toggle };
};
export default useToggle;

버튼 클릭하면 useToggle이라는 훅이 실행되며 true일땐 "켜짐" false일땐 "꺼짐"으로 변경된다.

import React from 'react';
import useToggle from './hooks/useToggle';

function App() {
  const { isOn, toggle } = useToggle(false);
  return (
    <div className="App">
      <button
        onClick={() => {
          toggle();
        }}
      >
        {isOn ? '켜짐' : '꺼짐'}
      </button>
    </div>
  );
}

export default App;

 

 

 


나만의 훅 만들어서 사용하기

import React, { useState } from "react";
import "./App.css";

// 나만의 훅 만들기
const useUser = () => {
  // useState()를 이용해 state 변수를 만드세요.
  const [nickname, setNickname] = useState("");

  const updateNickname = (event) => {
    const nickname = event.target.value;
    setNickname(nickname);
  };

  return [nickname, updateNickname];
};



// 내가 만든 나만의 훅 가져다 쓰기
const App = () => {
  // React Hook을 호출하세요.
  const [nickname, setNickname] = useUser();

  return (
    <div>
      <label>{nickname}</label>
      <br />
      <input value={nickname} onChange={setNickname} />
    </div>
  );
};

export default App;
반응형

'프론트엔드 > react.js' 카테고리의 다른 글

[React.js] Form, State, CSS 이용한 To-Do-List  (0) 2022.11.21
[React.js] 이벤트 처리  (0) 2022.11.15
[React.js] State  (0) 2022.11.14
[React.js] Prop  (0) 2022.11.14
[React.js] JSX와 컴포넌트  (0) 2022.11.14
반응형

 

 

 

 

extension

공식 문서 https://eslint.org/docs/latest/rules/

 

Rules - ESLint - Pluggable JavaScript Linter

A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript. Maintain your code quality with ease.

eslint.org

1. ESLint :

자바스크립트, 타입스크립트 코드의 규칙을 검사해주는 기능

.eslintrc.js 파일에서 규칙을 정의해준다.

 

2. .prettierrc

코드를 통일된 규칙으로 변경해주는 기능

ex) 따옴표를 싱글/더블 등으로 지정, 세미콜론 유무 등

 

반응형
반응형

이벤트

웹 브라우저가 알려주는 HTML요소에 대한 사건 발생

사용자의 행동에 의해 발생하거나, 개발자가 의도한 로직에 의해 발생한다.

 

 

DOM 이벤트 종류

onClick - element 클릭을 감지

onChange - element 내용(input의 텍스트 변경, 파일선택 등) 변경 감지

onKeyDown, onKeyUp, onKeyPress - 키보드 입력을 감지

onDoubleClick - element를 더블클릭 했을 때

onFocus - element에 마우스가 포커스 됐을 때

onBlur - element가 포커스를 잃었을 때

onSubmit - 폼 element에서 제출했을 때

 

 

이벤트 핸들러 함수

발생된 이벤트를 자바스크립트를 이용해 대응할 수 있다. 

이벤트 핸들러 함수안에 다양한 로직을 처리하고, 그 결과를 사용자에게 출력하여 알릴 수도 있다.

 

 

이벤트 처리 방법

(1) 핸들링 함수를 선언

import React from 'react';

function App() {
	
  const handleChange = event => {		// 핸들링 함수를 선언
    console.log(event);
  };
  
  return (
    <div className="App">
      <input onChange={handleChange} />		// input element와 핸들링 함수를 연결
    </div>
  );
}

export default App;

 

(2) 익명함수를 선언

import React from 'react';

function App() {
  return (
    <div className="App">
        <input onChange={(event) => {			// 이벤트 익명함수로 작성
            console.log(event.target.value)
        }}/>
    </div>
  );
}

export default App;

 

 


 

컴포넌트 내 이벤트 처리

 

(1) DOM 버튼 클릭

DOM element의 클릭 이벤트를 전달받아 처리

// src/App.js 파일

import React from 'react';
import Greeting from './components/Greeting';
function App() {
  return (
    <div className="App">
      <Greeting />			// 컴포넌트 삽입
    </div>
  );
}

export default App;
// src/components/Greeting.js

import React from 'react';

const Greeting = () => {
  const handleClick = () => {						// 컴포넌트 내에 이벤트 정의
    alert('안녕하세요');
  };
  return <button onClick={handleClick}>클릭</button>;			// 컴포넌트 내 이벤트 처리
};

export default Greeting;

 

 

(2) event와 state 연동하기

React로 애플리케이션을 개발하다보면

실시간으로 사용자로부터 값을 전달받아 컴포넌트에 반영할 일이 많기 때문에

이벤트와 State는 뗄래야 뗄 수 없는 관계라고 할 수 있다.

import React, { useState } from 'react'; 		// state를 쓰기 위해 useState 추가

function App() {
  const [inputValue, setInputValue] = useState('');	// state는 반드시 한쌍으로 정의됨
  return (
    <div className="App">
      <input
        onChange={event => {
          setInputValue(event.target.value);		// state는 반드시 set으로 저장되어야 함.
        }}
      ></input>
      <span>{inputValue}</span>				// stat는 변수처럼 가져다 사용 가능
    </div>
  );
}

export default App;

event.target.value : event object의 target은 이벤트의 원인이 되는 element를 가리킨다.

 

 

(3) 한개의 이벤트 핸들러를 이용해 여러 element에 재사용하기

state를 여러 개 선언할 수도 있지만 object를 활용하여 여러개의 input을 state로 관리하는 방법이 있다.

 

import React, { useState } from 'react';
function App() {

  // state를 object로 선언
  const [person, setPerson] = useState({
    name: '김민수',
    school: '엘리스대학교',
  });

  // 이벤트 핸들러 선언
  const handleChange = event => {
    const { name, value } = event.target;
    setPerson(current => {
      const newPerson = { ...current };
      newPerson[name] = value;
      return newPerson;
    });
  };
  
  
  return (
    <div className="App">
      // element 2개(input name, input school)에서 같은 핸들러함수 호출 가능
      <input name="name" value={person.name} onChange={handleChange}></input>
      <input name="school" value={person.school} onChange={handleChange}></input>
      
      <button
        onClick={() =>
          alert(`${person.name}님은 ${person.school}에 재학 중입니다.`)
        }
      >
        클릭
      </button>
    </div>
  );
}

export default App;

 

 


컴포넌트 외부로부터 이벤트를 전달받아 처리하기

 

(1) 컴포넌트 간 이벤트 전달하기

부모 컴포넌트에서 생성된 이벤트 핸들링 함수를 자식 컴포넌트로 전달하여 처리할 수 있다

 

src/components 디렉토리를 생성하고 MyForm.js 파일을 생성합니다.
MyForm 컴포넌트를 선언합니다. 
이 컴포넌트는 onChange 라는 함수를 Props로부터 전달받습니다.
MyForm 컴포넌트에서 <input> element를 반환. 
생성한 input element에 Props로부터 전달받은 onChange 함수를 전달
App.js로 돌아와 MyForm 컴포넌트를 import합니다.
username state를 선언합니다. 초기값은 ""입니다.
className이 "App"인 div 안에 <h1> element를 생성하고 내용은 OOO님 환영합니다.가 출력되도록 합니다.
(OOO에는 username state가 대입돼야 합니다.)
<h1> element 아래에
// app.js 파일

import React, { useState } from 'react';
import MyForm from './components/MyForm.js';

function App() {
  const [username, setUsername] = useState('');
  return (
    <div className="App">
      <h1>{username}님 환영합니다.</h1>
      <MyForm
        onChange={event => {
          setUsername(event.target.value);
        }}
      />
    </div>
  );
} 

export default App;
// components/MyForm.js

import React from 'react';

const MyForm = ({ onChange }) => {
  return <input onChange={onChange} />;
};

export default MyForm;

 

(2) 커스텀 이벤트

단순히 DOM 이벤트를 활용하는 것을 넘어서 나만의 이벤트를 만들 수도 있다.

 

 

이벤트 명명법

직접 이벤트를 만들 때에는 이름을 자유롭게 설정할 수 있다.

보톤은 on+동사 또는 on+명사+동사 형태로 작성한다.

 

 

 

 

반응형

'프론트엔드 > react.js' 카테고리의 다른 글

[React.js] Form, State, CSS 이용한 To-Do-List  (0) 2022.11.21
[React.js] Hooks  (0) 2022.11.21
[React.js] State  (0) 2022.11.14
[React.js] Prop  (0) 2022.11.14
[React.js] JSX와 컴포넌트  (0) 2022.11.14
반응형

State란

State는 컴포넌트 내에서 유동적으로 변할 수 있는 값을 저장한다.

즉, State는 컴포넌트 내에서 지속적으로 변경이 일어나는 값을 관리하기 위해 사용

개발자가 의도한 동작에 의해 변할 수도 있고, 사용자 입력에 따라 변할 수 있다.

State값이 변경되어 재렌더링이 필요한 경우, 

React가 자동으로 계산하여 변경된 부분만을 렌더링한다.

 

- State값은 직접 변경해서는 안된다. setState로 변경하지 않는다면, 리액트가 변화를 인지하지 못한다.

- Object를 갖는 State를 만들 때, Object의 값을 변경하려면 새로운 객체를 만들어 수정해야 한다.

 

 

State 선언방법

(1) useState

import { useState } from "react";		// useState를 import 해야함

const App = () => {
    const [value, setValue] = useState(초기값);	// [stateName, setStateName]으로 선언
    return ...
}

 

(2) setState : 값 변경

const [value, setValue] = useState("");

setValue("안녕하세요");

 

 

지시사항

  1. React 패키지로부터 useState를 import 하세요.
  2. App 컴포넌트 내에 count state를 선언합니다. 초기값은 0입니다.
    const [count, setCount] = useState(0);
  3. className이 App인 div 안에 <span>과 <button>을 각각 작성하세요.
  4. 작성한 span element에 X회 클릭하였습니다. 라는 문구를 작성합니다. X에는 선언한 count가 들어가야합니다.
  5. 작성한 button에 onClick 이벤트 처리 함수를 작성합니다. click 시 setCount를 이용해 count가 1씩 증가할 수 있도록 합니다. 이벤트 처리 함수는 다음과 같이 작성합니다.
import React, { useState } from 'react';

function App() {
  //  [stateName, setStateName]으로 선언
  const [count, setCount] = useState(0);

  return (
    <div className="App">
      <span>{count}회 클릭하였습니다.</span>
      <button
        onClick={() => {
          setCount((current) => {
            return current + 1;
          });
        }}
      >
        클릭
      </button>
    </div>
  );
}

export default App;

 

 


 

Object를 갖는 State

State는 string과 number 뿐만 아니라 object나 array도 값으로 할당할 수 있습니다.
그러나 object나 array의 값을 변경하기 위해서는 주의해야할 점이 있습니다.
바로 object나 array 내부의 값만 변경할 경우 React가 새로운 값으로 변경된 것을 인지하지 못한다는 것인데요.
object나 array를 값으로 갖는 state를 다룰 때 어떻게 코드를 작성해야하는 지 알아봅시다.

 

잘못된 예

const App = () => {
    const [person, setPerson] = useState({
        name: "민수",
        age: 23
    });
    .
    .
    .
    setPerson((current) => {
        current.age = 24;
        return current;
    })
}

위 예시의 코드를 실행할 경우 state가 변경되더라도 컴포넌트가 다시 렌더링되지 않습니다. 이유는 person 내부의 값은 변경되었지만 person 자체가 변경된 것은 아니기 때문이죠.
예를 들어 박스 안에 사과가 있는데 이 사과를 꺼내고 배를 넣었다고 해서 박스는 바뀌지 않는 것 처럼요. React는 박스 자체가 바뀔 경우에만 변경을 인지하고 다시 렌더링을 하게 됩니다.

 

올바른 예

const App = () => {
    const [person, setPerson] = useState({
        name: "민수",
        age: 23
    });
    .
    .
    .
    setPerson((current) => {
        const newPerson = {...current}; // Spread syntax(전개구문)를 이용해 object를 복사했습니다.
        newPerson.age = 24;
        return newPerson;
    })
}

 

 

 


import React, { useState } from 'react';

function App() {
  const [person, setPerson] = useState({
    name: '김민수',
    count: 0,
  });
  return (
    <div className="App">
      <button
        onClick={() => {
          setPerson(current => {
            const newPerson = { ...current };
            newPerson.count = newPerson.count + 1;
            return newPerson;
          });
        }}
      >
        클릭
      </button>
      <span>{person.name}님이 버튼을 {person.count}회 클릭하였습니다.</span>
    </div>
  );
}

export default App;
반응형

'프론트엔드 > react.js' 카테고리의 다른 글

[React.js] Hooks  (0) 2022.11.21
[React.js] 이벤트 처리  (0) 2022.11.15
[React.js] Prop  (0) 2022.11.14
[React.js] JSX와 컴포넌트  (0) 2022.11.14
[React.js] 리액트 프로젝트 생성  (0) 2022.11.14

+ Recent posts