버튼 렌더링 시 양식 이벤트 발생: React 렌더링 프로세스의 성가신 문제

12599 단어 reactjavascript
이 게시물은 문제와 그 원인 및 해결책을 설명하는 메모입니다.

사용자 정보를 가져와 목록으로 보여주는 웹 앱을 만들었습니다. 편집하거나 삭제하는 기능도 있습니다.

최종 코드는 here 입니다.



이슈가 뭐야?



문제는 편집 버튼이 작동하지 않는 것 같았습니다.

문제가 있는 구성 요소의 코드는 here 입니다.
코드here와 상호 작용할 수도 있습니다.

원인은 무엇입니까?



실제로 편집 버튼은 잘 작동합니다.

작동하지 않는 것처럼 보이는 이유는 구성 요소가 다시 렌더링된 후 편집 버튼onClick 이벤트가 종료되기 때문입니다.

점검



추가console.log하고 편집 버튼을 클릭하면 어떻게 되는지 확인했습니다.

loaded!  // the page loaded
editComment is now: false // initial state

// click the edit button

Edit button is clicked! 
editComment is now: true 
handleSave is called! 
editComment is now: false 


로그에 따르면 후드 아래에서 다음이 발생합니다.
  • 편집 버튼을 클릭합니다.
  • 편집 버튼의 onClick 이벤트가 실행되고 현재 editComment인 상태true를 업데이트합니다. (초기 상태는 false였습니다)
  • 구성 요소가 다시 렌더링됩니다.
  • handleSave 함수가 어떤 이유로 실행되고 상태 editComment를 다시 false로 업데이트합니다.
  • 구성 요소가 다시 렌더링됩니다.

  • 편집 버튼은 작동하지만 저장 버튼handleSave 기능이 동시에 실행됩니다.

    이러한 일들이 매우 빠르게 일어나기 때문에 우리는 그것을 볼 수 없으며 편집 버튼이 작동하지 않는 것 같습니다.

    다음 코드는 주석 구성 요소의 렌더링 부분을 단순화한 버전입니다.

    render(){
      return this.state.editComment ? (
        <tr>
         <td><form id="form1" onSubmit={this.handleSave}></form></td>
         <td><input form="form1" type="text" name="name"/></td>
         <td><input form="form1" type="email" name="email"/></td>
         <td><input form="form1" type="text" name="body" /></td>
         <td><button form="form1" type="submit">Save</button></td>
        </tr>
      ):(
      <tr>
       <td />
       <td>{this.state.name}</td>
       <td>{this.state.email}</td>
       <td>{this.state.body}</td>
       <td>
        <button onClick={() => this.setState({ editComment: true })}>Edit</button>
        <button onClick={() => handleDelete()}>Delete</button>
       </td>
      </tr>
      )
    }
    


    상태editComment는 처음에는 false이므로 아직 form 및 저장 버튼이 없어야 합니다.

    기이한!

    그렇다면 handleSave 함수가 호출되는 이유는 무엇입니까?
    다시 말하지만 구성 요소가 다시 렌더링된 후 편집 버튼의 이벤트onClick가 종료되기 때문입니다.

    사리



    편집 버튼을 클릭하면 form가 생성됩니다.

    편집 버튼과 저장 버튼은 비슷한 구조에 있기 때문에 React는 이 둘을 같은 유형의 DOM 요소로 간주합니다. 즉, React는 이 두 버튼을 구별할 수 없습니다.

    // simplified version
    // before re-render
      <tr>
       <td />
       <td>
        <button onClick={() => this.setState({ editComment: true })}>Edit</button>
        <button onClick={() => handleDelete()}>Delete</button>
       </td>
      </tr>
    
    
    
    // after re-render
      <tr>
       <td>
        <form id="form1" onSubmit={this.handleSave}></form>
       </td>
       <td>
        <button form="form1" type="submit">Save</button>
       </td>
      </tr>
    


    When comparing two React DOM elements of the same type, React looks at the attributes of both, keeps the same underlying DOM node, and only updates the changed attributes.



    https://reactjs.org/docs/reconciliation.html#dom-elements-of-the-same-type

    따라서 편집 버튼이 소멸되지 않습니다. 그것은 거기에 남아 있고 속성과 속성이 업데이트됩니다.

    말하자면 "저장"이라고 말하는 from="form1" 또는 type="submit"와 같은 추가 속성이 있는 편집 버튼입니다.

    그런 다음 여전히 버튼onClick이 지속됩니다.

    버튼의 onClick 이벤트가 종료되면 버튼은 form와 연결되어 handleSave 함수를 호출합니다.

    솔루션


  • 편집 버튼의 e.preventDefault()onClick를 추가합니다.onSubmit에서 handleSave (= form 함수)를 호출하지 않습니다.
  • render() 내부 조건의 기본이 되는 각 DOM에 대해 새 구성 요소를 만듭니다.
    컴포넌트를 다시 렌더링하면 기존 버튼(= 편집 버튼)이 업데이트되지 않고 새로운 버튼(= 저장 버튼)이 생성됩니다.
    편집 버튼의 이벤트onClick가 더 이상 수신되지 않습니다.
  • 편집 버튼과 저장 버튼에 각각 key를 추가합니다.key 를 추가하여 이 두 버튼이 다르다는 것을 React에 알립니다.
    https://reactjs.org/docs/reconciliation.html#keys



  • 분명히 이것은 매우 틈새 시장의 경우입니다.

    테이블 레이아웃을 사용하거나 양식 항목을 외부에 배치하면form 문제가 발생할 수 있습니다.

    구조를 구축할 때 접근성이나 가독성을 신중하게 고려하면 오류를 방지할 수 있습니다.

    이번에 배운 교훈입니다!

    감사의 말



    이 문제를 명확하게 이해하기 위해 여러 웹 개발자 커뮤니티에 들어가 이것에 대해 질문했습니다.

    이 문제를 해결하기 위해 저를 도와주신 커뮤니티의 분들께 진심으로 감사드립니다. 다시한번 정말 감사합니다🙏

    Kohei Asai , , Brandon Tsang , 에게 특별히 감사드립니다.

    좋은 웹페이지 즐겨찾기