Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

Joon's Space

[React] React Hooks (useState) 1 본문

Web/React

[React] React Hooks (useState) 1

Happy Joon 2021. 7. 18. 11:41

React Hooks 란?

react의 state machine에 연결하는 기본적인 방법. Hooks를 사용하면 기존의 class 방식을 더 이상 사용하지 않고, 함수형 프로그래밍 방식을 사용한다. 

 

useState

// App.js

import { useState } from "react";
import "./styles.css";

export default function App() {
  const [item, setItem] = useState(1); // state 초기값을 1로 설정해줌.
  const incrementItem = () => setItem(item + 1);
  const decrementItem = () => setItem(item - 1);
  return (
    <div className="App">
      <h1>Hello {item}</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={incrementItem}>Increment</button>
      <button onClick={decrementItem}>Decrement</button>
    </div>
  );
}

 

useState는 Array를 return 해야 한다. Array 첫 번째 요소는 item, 두 번째 요소는 setItem. 

 

return 안에 button을 만들어서 onClick={increment}, onClick={decrement} 로 연결해 준다.

 

만약 hooks를 사용하지 않고 기존처럼 class component 형식으로 작성한다면? 다음과 같이 코드가 길어진다. 

 

class AppUgly extends React.Component {
  state = {
    item: 1
  }

  render() {
    const {item} = this.state;
    return (
      <div className="App">
      <h1>Hello {item}</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={this.incrementItem}>Increment</button>
      <button onClick={this.decrementItem}>Decrement</button>
      </div>
    );
  }
  incrementItem = {
    this.setState(state => {
      return (
        item:state.item + 1
      );
    });
  };
  decrementItem = {
    this.setState(state => {
      return(
        item:state.item - 1
      );
    });
  };

}

 

- useInput

// App.js

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

const useInput = (initialValue, validator) => {
  const [value, setValue] = useState(initialValue);
  const onChange = (event) => {
    const {
      target: { value }
    } = event;
    setValue(value);
  };
  return { value, onChange };
};
export default function App() {
  const name = useInput("Mr.");
  return (
    <div className="App">
      <h1>Hello</h1>
      <input placeholder="Name" {...name} />
    </div>
  );
}

다음과 같이 initialValue 를 꼭 정해주는 것이 아니라, App function 안에서 useInput을 이용해서 정해 줄 수 있다. 

 

value = {name.value}, onChange = {name.onChange} 부분을 useInput의 return으로 value, onChange 모두 {...name}으로  unpack 할 수 있다. 

 

placeholder 안에 'Mr.' 가 적혀있고 커서를 누르고 키보드를 누르면 input 안의 값이 바뀐다.

// App.js

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

const useInput = (initialValue, validator) => {
  const [value, setValue] = useState(initialValue);
  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;
  const name = useInput("Mr.", maxLen); // validator는 maxLen 이다.
  return (
    <div className="App">
      <h1>Hello</h1>
      <input placeholder="Name" {...name} />
    </div>
  );
}

useInput을 정의해줄 때 initialValue 이외 validator라는 function을 parameter로 받아주어 내가 설정한 유효성(검증성)을 확인하게 해주는 기능을 테스트한다. App()에서는 maxLen 함수가 validator가 되어 value.length가 10개 이상이면 willUpdate가 false가 되어 더 이상 value가 변하지 않게 한다. 

 

또한 validator 함수 리턴값에 value.includes를 이용하여 입력에 꼭 필요한 문자, 넣으면 안 되는 문자를 정해 줄 수 있다.

 

9글자를 넘어서 입력했을 때 더이상 입력되지 않는 것을 확인 할 수 있다.

 

- useTabs

 

// App.js

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

const content = [
  {
    tab: "Section 1",
    content: "I'm the content of the Section 1"
  },
  {
    tab: "Section 2",
    content: "I'm the content of the Section 2"
  }
];

const useTabs = (initialTab, allTabs) => {
  if(!allTabs || !Array.isArray(allTabs)){ // allTabs가 존재하지 않거나, 배열이 아닌 경우 실패
    return;
  }
  const [currentIndex, setCurrentIndex] = useState(initialTab);
  return {
    currentItem: allTabs[currentIndex],
    changeItem: setCurrentIndex
  };
};

export default function App() {
  const { currentItem, changeItem } = useTabs(0, content); // 배열의 인덱스 0 부터 시작.
  return (
    <div className="App">
      {content.map((section, index) => (
        <button onClick={() => changeItem(index)}>{section.tab}</button>
      ))} 
      <div>{currentItem.content}</div>
    </div>
  );
}

object type인 content를 하나 생성한 뒤, 이것을 control하는 useTabs를 생성해준다. 

 

content는 array이어야 하고, 각 원소들은 object type으로 구성되어 있다. section의 개수만큼 button을 생성해주고, 그 해당하는 버튼을 클릭했을 때(onClick), tabs의 index번호가 클릭한 번호로 set 되게 한다.  onClick 괄호 안에는 클릭했을 때 실행되는 함수가 있어야 하는데 ()로 이름 없는 함수가 정의될 수도 있다. ( setCurrentIndex()를 이용한다. )

 

 

각 section을 클릭 했을 때, 해당하는 section의 content 내용이 load 되는 것을 확인 할 수있다.

 

 

반응형