06. Event

들어가기전

React 에서는 직접적인 DOM 의 접근보다는 State 라는 상태 값을 이용하여 DOM 에 변화를 준다고 했습니다. 이번에는 Event 를 학습하여 State 를 다양하게 변경하는 방법에 대해서 알아보려고합니다.

실습

프로젝트는 초기 세팅 상태로 진행되어집니다. +@ 로 이제는 styled-component 를 이용하기 때문에 App.css 파일이 필요없습니다.

우리가 입력하는 값에 따라서 넓이, 높이, 색상을 가진 박스를 만들어보고자 합니다.

Input 에 값을 입력하여 입력된 값을 바탕으로 상자를 만들고 싶습니다. 먼저 Input, Label Component 를 만들어보겠습니다.

// App.js

import React from 'react'
import styled from 'styled-components'

const Label = styled.h2`
  color: #333;
`

const Input = styled.input`
  padding: 10px 20px;
`

class App extends React.Component {
  render () {
    return (
      <div>
        <Label>Width</Label>
        <Input />
        <Label>Height</Label>
        <Input />
        <Label>Color</Label>
        <Input />
      </div>
    )
  }
}

export default App

Box Component 를 준비합니다. Box 는 넓이, 높이, 색상을 Prop 로 받아 스타일을 구성합니다.

const Box = styled.div`
  ${({ width, height, color }) => 
    width && height && color && css`
    width: ${width}px;
    height: ${height}px;
    background-color: ${color};
  `}
`

이번에는 Box 에게 넘겨줄 State 를 추가합니다. 그리고 추가된 State 를 Box 에게 넘겨줍니다.

// App.js

import React from 'react'
import styled, { css } from 'styled-components'

const Label = styled.h2`
  color: #333;
`

const Input = styled.input`
  padding: 10px 20px;
`

const Button = styled.button`
  display: block;
  background: #03A9F4;
  border: none;
  color: #fff;
  font-weight: bold;
  border-radius: 4px;
  padding: 5px 10px;
  margin-top: 20px;
`

const Box = styled.div`
  ${({ width, height, color }) => 
    width && height && color && css`
    width: ${width}px;
    height: ${height}px;
    background-color: ${color};
  `}
`

class App extends React.Component {
  state = {
    width: 0,
    height: 0,
    color: ''
  }

  render () {
    const { width, height, color } = this.state 

    return (
      <div>
        <Label>Width</Label>
        <Input />
        <Label>Height</Label>
        <Input />
        <Label>Color</Label>
        <Input />
        <Box width={width} height={height} color={color} />
      </div>
    )
  }
}

export default App

우리가 원하는 것은 Input 에 값을 입력하고 Input 에 맞는 State 가 변경이되면서 변경된 값이 Box 에게 전달되기를 원합니다.

Input 의 onChange Event 를 추가하여 바뀌는 값을 캐치해보겠습니다.

// App.js

import React from 'react'
import styled, { css } from 'styled-components'

const Label = styled.h2`
  color: #333;
`

const Input = styled.input`
  padding: 10px 20px;
`

const Box = styled.div`
  ${({ width, height, color }) => 
    width && height && color && css`
    width: ${width}px;
    height: ${height}px;
    background-color: ${color};
  `}
`

class App extends React.Component {
  state = {
    width: 0,
    height: 0,
    color: ''
  }

  handleStyles = (e) => {
    console.log(e.target)
  }

  render () {
    const { state: { width, height, color }, handleStyles } = this 

    return (
      <div>
        <Label>Width</Label>
        <Input name="width" onChange={handleStyles}/>
        <Label>Height</Label>
        <Input name="height" onChange={handleStyles} />
        <Label>Color</Label>
        <Input name="color" onChange={handleStyles} />
        <Box width={width} height={height} color={color} />
      </div>
    )
  }
}

export default App

각 Input 들은 onChange 를 통해 handleStyles 함수를 호출합니다. handleStyles 함수는 event 객체를 넘겨받습니다. event 객체에는 해당 이벤트에 대한 정보를 담고있습니다. Input 들은 name 값을 가지고 있고 Input 이기 때문에 value attribute 를 가지고 있습니다. 우리는 이 값들을 이용하여 state 를 변경하려고합니다.

JSX 에서 Event 를 걸어줄때는 함수를 JSX 내부가 아닌 class 아래쪽으로 빼주는 것이 좋습니다.

handleStyles 함수에 넘어오는 event 객체를 통해 Input 의 name 과 value 를 가져옵니다.

// App.js

handleStyles = ({ target: { name, value }}) => {
  console.log(name, value)
}

이제 이 값들을 이용해서 State 의 정보를 update 합니다. State 를 update 할 때는 반드시 setState 라는 함수를 이용해야합니다.

기존의 State 들은 유지하면서 새로 들어온 key, value 값만 update 합니다.

// App.js

handleStyles = ({ target: { name, value }}) => {
  this.setState({ ...this.state, [name]: value })
}

Hook 을 이용하기

hook 은 위에서 알아본 Class Component 와는 살짝 다릅니다. State 선언과 update는 useState 라는 것을 이용합니다.

// App.js

import React, { useState } from 'react'
import styled, { css } from 'styled-components'

const Label = styled.h2`
  color: #333;
`

const Input = styled.input`
  padding: 10px 20px;
`

const Box = styled.div`
  ${({ width, height, color }) => 
    width && height && color && css`
    width: ${width}px;
    height: ${height}px;
    background-color: ${color};
  `}
`

function App () {
  const [styles, setStyles] = useState({
    width: 0,
    height: 0,
    color: ''
  })

  const handleStyles = ({ target: { name, value }}) => {
    setStyles({ ...styles, [name]: value })
  }

  const { width, height, color } = styles 

  return (
    <div>
      <Label>Width</Label>
      <Input name="width" onChange={handleStyles}/>
      <Label>Height</Label>
      <Input name="height" onChange={handleStyles} />
      <Label>Color</Label>
      <Input name="color" onChange={handleStyles} />
      <Box width={width} height={height} color={color} />
    </div>
  )
}

export default App

Last updated