My Develop Log

[노마드코더]실전형 리액트 Hooks 10개 - (useState, useInput, useTabs) 노트정리 본문

React 공부

[노마드코더]실전형 리액트 Hooks 10개 - (useState, useInput, useTabs) 노트정리

Developer_Sammy 2023. 1. 5. 17:26
useState

가장 간단한 Counter 예제를 살펴보면  useState의 역할을 이해하기 쉽다.

// App.js

import React, { useState } from "react";

export default function App() {
  const [item, setItem] = useState(0);
  let increase = () => {
    setItem(item + 1);
  };
  let decrease = () => {
    setItem(item - 1);
  };
  return (
    <div>
      my number : {item} <br />
      <button onClick={increase}>Increase</button>
      <button onClick={decrease}>Decrease</button>
    </div>
  );
}
// index.js

import { createRoot } from "react-dom/client";
import App from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(<App />);

1. 우선 useState를 선언해준다.

// App.js

const [item, setItem] = useState(0);

2. increase, decrease 함수를 정의한다. 이때, setItem을 통해 item의 값을 변경 시킬 수 있다.

// App.js
let increase = () => {
    setItem(item + 1);
  };
  
let decrease = () => {
    setItem(item - 1);
  };

3. 각각의 함수를 버튼에 연결시켜주고 return 해준다.

// App.js

return (
    <div>
      my number : {item} <br />
      <button onClick={increase}>Increase</button>
      <button onClick={decrease}>Decrease</button>
    </div>
  );

4. index.js에서 <App />을 렌더링해준다.

// index.js
root.render(<App />);

 


useInput

useInput은 커스터 Hooks로 hook을 활용하여 input에 값을 입력할 때 state 변경 및 validator를 통해 검증을 할 수 있고, 이를 바탕으로 input을 업데이트 해준다. 이러한 useInput을 잘 활용하면 input을 받을때 유효성 검사 처리하는데 유용하게 사용될 것 같다. 

// App.js

import React, { useState } from 'react';

const useInput = (element, validator) => { 
  const [value, setValue] = useState(element);
  
  const onChange = event => {
    const {target: { value }} = event;
    let willUpdate = true;
    
    if (typeof validator === "function") {
      willUpdate = validator(value);
    }
    
    if (willUpdate) {
      setValue(value);
    }
  };

  return { value, onChange };
};

export default function App(){
  const maxLen = value => value.length < 10; // 입력할 때 길이가 10을 넘지 않게 하는 validator 함수
  const check = value => !value.includes("@"); // 입력할 때 "@"를 못치게 하는 validator 함수
  const name = useInput("Mr.", maxLen);
  
  return (
    <div className="App">
      <input placeholder="name" {...name} />
    </div>
  );
};
// index.js

import { createRoot } from "react-dom/client";
import App from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(<App />);

1. useInput 함수는 args로 element를 받는 useState를 작성해주고, name을 "Mr."로 기본값 설정한다.

// App.js

function useInput (element, validator){
  const [ value, setValue ] = useState(element);
  
  return {value}
}
// App.js

export default function App(){

  return (
    <div className="App">
      <input placeholder="name" {...name} />
    </div>
  );
};
  • value={name.value} 대신에 {...name}으로 사용가능한데 이는 name 안에 있는 모든것을 펼친다는 뜻이다.

2. onChange 함수를 만들어 useInput 함수 안에 추가해준다. onChange 같은 경우는 항상 event와 함께 사용해준다. onChange 함수에서 중요한 점은 validator라는 검사를 통해 value의 값을 업데이트 시켜준다는 점이다.

// App.js

const useInput = (element, validator) => { 
  const [value, setValue] = useState(element);
  
  const onChange = event => {
    const {target: { value }} = event;
    let willUpdate = true;
    
    if (typeof validator === "function") {
      willUpdate = validator(value);
    }
    
    if (willUpdate) {
      setValue(value);
    }
  };

  return { value, onChange };
};

export default function App(){
  const maxLen = value => value.length < 10; // 입력할 때 길이가 10을 넘지 않게 하는 validator 함수
  const check = value => !value.includes("@"); // 입력할 때 "@"를 못치게 하는 validator 함수
  
  const name = useInput("Mr.", maxLen);
  
  return (
    <div className="App">
      <input placeholder="name" {...name} />
    </div>
  );
};
  •  onChange 함수에서 args로 받은 validator 함수를 통해 검사 후, 결과가 True일 경우 setValue를 통해 value 값을 변경 시켜준다.

useTabs

useTabs는 버튼을 클릭했을 때 해당 버튼의 내용을 다르게 보여주도록 할 수 있는 커스텀 Hooks이다.

//App.js

const content = [
  {
    tab: "Section 1",
    content: "This is the content of the Section 1"
  },
  {
    tab: "Section 2",
    content: "This is the content of the Section 2"
  }
];

const useTabs = (initialTab, allTabs) => {
  const [currentIndex, setCurrentIndex] = useState(initialTab);

  if (!allTabs || !Array.isArray(allTabs)) { 
    return; // useTabs를 사용시 allTabs 매개변수를 쓰지 않거나,배열이 아닐시 에러가 뜨지 않게 return
  }

  return {
    currentItem: allTabs[currentIndex],
    changeItem: setCurrentIndex
  };
};

export default function App(){
  const { currentItem, changeItem } = useTabs(0, content);

  return (
    <div className="App">
      {content.map((section, index) => (
        <button onClick={() => changeItem(index)}>{section.tab}</button>
      ))}
      <div>{currentItem.content}</div>
    </div>
  );
};
// index.js

import { createRoot } from "react-dom/client";
import App from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(<App />);

1. 우선 사용할 content를 다음과 같이 배열에 저장한다.

// App.js

const content = [
  {
    tab: "Section 1",
    content: "This is the content of the Section 1"
  },
  {
    tab: "Section 2",
    content: "This is the content of the Section 2"
  }
];

2. useTabs 함수 args로 초기 tab인덱스인 initialTab과 tabs 데이터인 allTabs를 매개변수로 받는다. useState를 활용하여 currentIndex 변수를 만들어주고, currentItem과 changeItem을 반환해준다. 이때, currentItem은 어떤 content인지, changeItem은 useState로 만든 currentIndex의 값을 변경시켜주는  setCurrentIndex 함수이다.

//App.js

const useTabs = (initialTab, allTabs) => {
  const [currentIndex, setCurrentIndex] = useState(initialTab);

  if (!allTabs || !Array.isArray(allTabs)) { 
    return; // useTabs를 사용시 allTabs 매개변수를 쓰지 않거나,배열이 아닐시 에러가 뜨지 않게 return
  }

  return {
    currentItem: allTabs[currentIndex],
    changeItem: setCurrentIndex
  };
};

3. useTabs를 통해 0과 미리 만들어둔 content를 인자로 넘김으로써 해당 content인 currentItem과 changeItem함수를 전달받고 각 section 마다의 버튼을 생성 후 onClick으로 연결시켜준다.

// App.js

export default function App(){
  const { currentItem, changeItem } = useTabs(0, content);

  return (
    <div className="App">
      {content.map((section, index) => (
        <button onClick={() => changeItem(index)}>{section.tab}</button>
      ))}
      <div>{currentItem.content}</div>
    </div>
  );
};

 

Reference

https://nomadcoders.co/react-hooks-introduction/lobby

 

실전형 리액트 Hooks 10개 – 노마드 코더 Nomad Coders

Build your own Hooks Library

nomadcoders.co