본문 바로가기

React

이슈 12 react form 초기화하는 세 가지 방법

반응형

react에서 form을 초기화하는 데에는 세 가지 방법이 있습니다.

  1. js의 event.target.reset()을 이용하는 방법
  2. react의 ref를 이용하는 방법
  3. react의 key를 이용하는 방법

js의 event.target.reset()을 이용하는 방법

event.target.reset()을 테스트 해보기 위해 아래와 같은 코드를 작성합니다. 직접 값을 입력하는 input과, 버튼을 눌렀을 때 값이 증가하는 input, submit 버튼이 표시됩니다. 물론 state를 끌어올리는 게 최상이지만, 그럴 수 없는 상황이라고 가정합니다. state를 끌어올리는 방법에 대해서는 아래 링크를 참고해주세요.

 

State 끌어올리기 – React

A JavaScript library for building user interfaces

ko.reactjs.org

class Child extends Component {
  state = {
    value: ''
  }

  setValue = (event) => {
    event.preventDefault()
        this.setState({ value: 1 + +this.state.value })
  }

  render () {
    return(
      <div>
        <input value={this.state.value} />
        <button onClick={this.setValue}>+1</button>
      </div>
    )
  }
}

class ResetForm extends Component {
    handleSubmit = (event) => {
    event.preventDefault()
        /* do something using event.target */
    event.target.reset()
  }

    render () {
        return (
      <form onSubmit={this.handleSubmit}>
                <input placeholder={"input..."}/>
        <Child />
        <button>submit & clear</button>
      </form>
    )
  }
}

이 방법은 자바스크립트 form 태그 자체의 기능을 이용하는 것이기 때문에, 자식 컴포넌트의 state까지 초기화 할 수 없습니다.

react의 ref를 이용하는 방법

react 공식 문서에서는 ref가 무엇인지, ref를 언제 사용해야 할 지에 대해 한국어로 자세히 설명하고 있습니다.

 

Ref와 DOM – React

A JavaScript library for building user interfaces

ko.reactjs.org

간단히 설명하자면, ref.current를 사용해서 자식 컴포넌트에 간섭할 수 있습니다.

class Child extends Component {
  state = {
    value: ''
  }

  setValue = (event) => {
    event.preventDefault()
        this.setState({ value: 1 + +this.state.value })
  }

  render () {
    return(
      <div>
        <input value={this.state.value} />
        <button onClick={this.setValue}>+1</button>
      </div>
    )
  }
}

class ResetForm extends Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
  }

    handleSubmit = (event) => {
    event.preventDefault()
        this.myRef.current.setState({ value: '' })
    event.target.reset()
  }

    render () {
        return (
      <form onSubmit={this.handleSubmit}>
                <input placeholder={"input..."}/>
        <Child ref={this.myRef}/>
        <button>submit & clear</button>
      </form>
    )
  }
}

자식 컴포넌트의 state가 많을 경우, 아래와 같이 사용할 수도 있습니다.

class ResetForm extends Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
  }

    handleSubmit = (event) => {
    event.preventDefault()
        const child = this.myRef.current
    const state = Object.keys(child.state).reduce(
      (arr, ele) => {
        arr[ele] = ''
        return arr
      }, {})
    child.setState(state)
    event.target.reset()
  }

    render () {
        return (
      <form onSubmit={this.handleSubmit}>
                <input placeholder={"input..."}/>
        <Child ref={this.myRef}/>
        <button>submit & clear</button>
      </form>
    )
  }
}

이는 권장되는 문법은 아닌 듯 합니다. 공식 문서에서는 가능하다면 DOM 노드를 외부에 공개하는 일을 지양해야 한다고 서술하고 있습니다. 여전히 유용하다는 입장이긴 하지만 말이죠.

react의 key를 이용하는 방법

ref보다 간단한 편법과도 같은 방법이 있습니다. react는 key를 사용하여 컴포넌트를 구별하고, 어떤 항목을 변경, 추가 또는 삭제할 지 결정합니다. 즉, key를 바꾸면 새로 랜더링 됩니다.

 

 

리스트와 Key – React

A JavaScript library for building user interfaces

ko.reactjs.org

class Child extends Component {
  state = {
    value: ''
  }

  setValue = (event) => {
    event.preventDefault()
        this.setState({ value: 1 + +this.state.value })
  }

  render () {
    return(
      <div>
        <input value={this.state.value} />
        <button onClick={this.setValue}>+1</button>
      </div>
    )
  }
}

class ResetForm extends Component {
    state = {
        key: 0
    }

    handleSubmit = (event) => {
    event.preventDefault()
        this.setState({
            key: this.state.key + 1
        })
    event.target.reset()
  }

    render () {
        return (
      <form onSubmit={this.handleSubmit}>
                <input placeholder={"input..."}/>
        <Child key={this.state.key}/>
        <button>submit & clear</button>
      </form>
    )
  }
}

이 방법은 간편하지만 단점이 있습니다. Child가 값을 비동기적으로 불러온다면 깜박임이 발생한다는 점인데요. 아래 코드를 통해 체험해볼 수 있습니다.

class Child extends Component {
  state = {
    value: ''
  }

  constructor(props) {
    super(props)
    setTimeout(
      () => this.setState({ value: 0 }),
      1000
    )
  }

  setValue = (event) => {
    event.preventDefault()
        this.setState({ value: 1 + +this.state.value })
  }

  render () {
    return(
      <div>
        <input value={this.state.value} />
        <button onClick={this.setValue}>+1</button>
      </div>
    )
  }
}

class ResetForm extends Component {
    state = {
        key: 0
    }

    handleSubmit = (event) => {
    event.preventDefault()
        this.setState({
            key: this.state.key + 1
        })
    event.target.reset()
  }

    render () {
        return (
      <form onSubmit={this.handleSubmit}>
                <input placeholder={"input..."}/>
        <Child key={this.state.key}/>
        <button>submit & clear</button>
      </form>
    )
  }
}

지금이야 일부러 setTimeout을 통해 값을 의도적으로 늦게 전달했지만, db에 저장된 값을 가져오는 상황이라면 충분히 비슷한 상황이 발생할 수 있습니다.

소감

오늘은 react에서 form을 초기화하는 세 가지 방법에 대해 알아봤습니다. 알아볼수록 state를 최상위에서 관리하는 게 중요하다는 느낌 밖엔 들지 않는군요... state를 끌어올리는 방법에 대해 더 알아봐야겠습니다.

반응형