Updating Other Content

μ‚¬λžŒλ“€μ΄ htmxλ₯Ό 처음 μ‚¬μš©ν•  λ•Œ 자주 λ¬»λŠ” 질문 쀑 ν•˜λ‚˜λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€:

β€œν™”λ©΄μ˜ λ‹€λ₯Έ μ½˜ν…μΈ λ₯Ό μ—…λ°μ΄νŠΈν•΄μ•Ό ν•©λ‹ˆλ‹€. μ–΄λ–»κ²Œ ν•΄μ•Ό ν•˜λ‚˜μš”?”

이 μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλŠ” μ—¬λŸ¬ 가지 방법이 있으며, 이 μ˜ˆμ œμ—μ„œλŠ” λͺ‡ 가지 방법을 μ•ˆλ‚΄ν•΄ λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€.

μ•„λž˜μ˜ κΈ°λ³Έ UIλ₯Ό μ‚¬μš©ν•˜μ—¬ 이 κ°œλ…μ„ μ„€λͺ…ν•˜κ² μŠ΅λ‹ˆλ‹€: κ°„λ‹¨ν•œ μ—°λ½μ²˜ ν…Œμ΄λΈ”κ³Ό, 이 ν…Œμ΄λΈ”μ— μƒˆλ‘œμš΄ μ—°λ½μ²˜λ₯Ό μΆ”κ°€ν•˜κΈ° μœ„ν•΄ hx-post을 μ‚¬μš©ν•˜λŠ” νΌμž…λ‹ˆλ‹€.

<h2>Contacts</h2>
<table class="table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th></th>
    </tr>
  </thead>
  <tbody id="contacts-table">
    ...
  </tbody>
</table>
<h2>Add A Contact</h2>
<form hx-post="/contacts">
  <label>
    Name
        <input name="name" type="text">  
  </label>
  <label>
    Email
        <input name="email" type="email">  
  </label>
</form>

μ—¬κΈ°μ„œ λ¬Έμ œλŠ”, νΌμ—μ„œ μƒˆλ‘œμš΄ μ—°λ½μ²˜λ₯Ό μ œμΆœν•  λ•Œ, μ—°λ½μ²˜ ν…Œμ΄λΈ”μ΄ μƒˆλ‘œ κ³ μΉ¨λ˜μ–΄ 방금 νΌμ—μ„œ μΆ”κ°€λœ μ—°λ½μ²˜λ₯Ό ν¬ν•¨ν•˜λ„λ‘ ν•΄μ•Ό ν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

μ–΄λ–€ 해결책이 μžˆμ„κΉŒμš”?

#ν•΄κ²°μ±… 1: νƒ€κ²Ÿ ν™•μž₯

μ—¬κΈ°μ„œ κ°€μž₯ κ°„λ‹¨ν•œ 해결책은 폼의 νƒ€κ²Ÿμ„ ν…Œμ΄λΈ”κ³Ό 폼을 λͺ¨λ‘ ν¬ν•¨ν•˜λ„λ‘ β€œν™•μž₯β€œν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, 전체λ₯Ό div둜 감싸고 νΌμ—μ„œ ν•΄λ‹Ή divλ₯Ό νƒ€κ²ŸμœΌλ‘œ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

<div id="table-and-form">
    <h2>Contacts</h2>
    <table class="table">
      <thead>
        <tr>
          <th>Name</th>
          <th>Email</th>
          <th></th>
        </tr>
      </thead>
      <tbody id="contacts-table">
        ...
      </tbody>
    </table>
    <h2>Add A Contact</h2>
    <form hx-post="/contacts" hx-target="#table-and-form">
      <label>
        Name
            <input name="name" type="text">  
      </label>
      <label>
        Email
            <input name="email" type="email">  
      </label>
    </form>
</div>

μ—¬κΈ°μ„œ μš°λ¦¬λŠ” hx-target 속성을 μ‚¬μš©ν•˜μ—¬ ν¬ν•¨ν•˜λŠ” divλ₯Ό νƒ€κ²ŸμœΌλ‘œ μ§€μ •ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. /contacts에 λŒ€ν•œ POST μ‘λ‹΅μ—μ„œ ν…Œμ΄λΈ”κ³Ό 폼을 λͺ¨λ‘ λ Œλ”λ§ν•΄μ•Ό ν•©λ‹ˆλ‹€.

이 방법은 κ°„λ‹¨ν•˜κ³  μ‹ λ’°ν•  수 μžˆμ§€λ§Œ, νŠΉλ³„νžˆ μš°μ•„ν•˜λ‹€κ³  λŠκ»΄μ§€μ§€λŠ” μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

#ν•΄κ²°μ±… 2: Out of Band Responses

이 문제λ₯Ό ν•΄κ²°ν•˜λŠ” 더 μ •κ΅ν•œ μ ‘κ·Ό 방식은 Out of Band μŠ€μ™‘μ„ μ‚¬μš©ν•˜μ—¬ DOM에 μ—…λ°μ΄νŠΈλœ μ½˜ν…μΈ λ₯Ό μ‚½μž…ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

이 방법을 μ‚¬μš©ν•˜λ©΄ HTML은 처음 μ„€μ •ν•œ κ·ΈλŒ€λ‘œ μœ μ§€λ  수 μžˆμŠ΅λ‹ˆλ‹€:

<h2>Contacts</h2>
<table class="table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th></th>
    </tr>
  </thead>
  <tbody id="contacts-table">
    ...
  </tbody>
</table>
<h2>Add A Contact</h2>
<form hx-post="/contacts">
  <label>
    Name
        <input name="name" type="text">  
  </label>
  <label>
    Email
        <input name="email" type="email">  
  </label>
</form>

ν”„λ‘ νŠΈ μ—”λ“œμ—μ„œ 무언가λ₯Ό μˆ˜μ •ν•˜λŠ” λŒ€μ‹ , /contacts에 λŒ€ν•œ POST μ‘λ‹΅μ—μ„œ 좔가적인 μ½˜ν…μΈ λ₯Ό 포함할 수 μžˆμŠ΅λ‹ˆλ‹€:

<tbody hx-swap-oob="beforeend:#contacts-table">
  <tr>
    <td>Joe Smith</td>
    <td>[email protected]</td>
  </tr>
</tbody>

<label>
  Name
      <input name="name" type="text">
</label>
<label>
  Email
      <input name="email" type="email">
</label>

이 μ½˜ν…μΈ λŠ” hx-swap-oob 속성을 μ‚¬μš©ν•˜μ—¬ #contacts-table에 μžμ‹ μ„ μΆ”κ°€ν•˜μ—¬ μ—°λ½μ²˜κ°€ μ„±κ³΅μ μœΌλ‘œ μΆ”κ°€λœ ν›„ ν…Œμ΄λΈ”μ„ μ—…λ°μ΄νŠΈν•©λ‹ˆλ‹€.

#ν•΄κ²°μ±… 3: 이벀트 트리거링

더 μ •κ΅ν•œ μ ‘κ·Ό 방식은 μ„±κ³΅μ μœΌλ‘œ μ—°λ½μ²˜κ°€ μƒμ„±λ˜μ—ˆμ„ λ•Œ ν΄λΌμ΄μ–ΈνŠΈ μΈ‘ 이벀트λ₯Ό νŠΈλ¦¬κ±°ν•˜κ³ , κ·Έ 이벀트λ₯Ό ν…Œμ΄λΈ”μ—μ„œ κ°μ§€ν•˜μ—¬ ν…Œμ΄λΈ”μ„ μƒˆλ‘œκ³ μΉ¨ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

<h2>Contacts</h2>
<table class="table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th></th>
    </tr>
  </thead>
  <tbody id="contacts-table" hx-get="/contacts/table" hx-trigger="newContact from:body">
    ...
  </tbody>
</table>
<h2>Add A Contact</h2>
<form hx-post="/contacts">
  <label>
    Name
        <input name="name" type="text">  
  </label>
  <label>
    Email
        <input name="email" type="email">  
  </label>
</form>

μ—¬κΈ°μ„œλŠ” μ—°λ½μ²˜ ν…Œμ΄λΈ”μ„ λ‹€μ‹œ λ Œλ”λ§ν•˜λŠ” /contacts/tableμ΄λΌλŠ” μƒˆλ‘œμš΄ μ—”λ“œν¬μΈνŠΈλ₯Ό μΆ”κ°€ν–ˆμŠ΅λ‹ˆλ‹€. 이 μš”μ²­μ˜ νŠΈλ¦¬κ±°λŠ” newContactμ΄λΌλŠ” μ‚¬μš©μž μ •μ˜ μ΄λ²€νŠΈμž…λ‹ˆλ‹€. 이 μ΄λ²€νŠΈλŠ” 폼의 응닡에 μ˜ν•΄ 트리거될 λ•Œ 이벀트 λ²„λΈ”λ§μœΌλ‘œ 인해 body에 λ„λ‹¬ν•˜κ²Œ λ˜λ―€λ‘œ, 이λ₯Ό bodyμ—μ„œ κ°μ§€ν•©λ‹ˆλ‹€.

/contacts둜의 POST μš”μ²­μ΄ μ„±κ³΅μ μœΌλ‘œ μ™„λ£Œλ˜μ–΄ μ—°λ½μ²˜κ°€ μƒμ„±λ˜λ©΄, μ‘λ‹΅μ—λŠ” λ‹€μŒκ³Ό 같은 HX-Trigger 응닡 헀더가 ν¬ν•¨λ©λ‹ˆλ‹€:

HX-Trigger:newContact

이 ν—€λ”λŠ” ν…Œμ΄λΈ”μ΄ /contacts/table둜 GET μš”μ²­μ„ 보내도둝 νŠΈλ¦¬κ±°ν•˜λ©°, 이λ₯Ό 톡해 μƒˆλ‘œ μΆ”κ°€λœ μ—°λ½μ²˜ ν–‰(및 ν…Œμ΄λΈ”μ˜ λ‚˜λ¨Έμ§€ λΆ€λΆ„)이 λ Œλ”λ§λ©λ‹ˆλ‹€.

μ•„μ£Ό κΉ”λ”ν•œ 이벀트 기반 ν”„λ‘œκ·Έλž˜λ° λ°©μ‹μž…λ‹ˆλ‹€!

#ν•΄κ²°μ±… 4: Path Dependencies ν™•μž₯ μ‚¬μš©

λ§ˆμ§€λ§‰ μ ‘κ·Ό 방식은 REST-ful 경둜 μ˜μ‘΄μ„±μ„ μ‚¬μš©ν•˜μ—¬ ν…Œμ΄λΈ”μ„ μƒˆλ‘œκ³ μΉ¨ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. htmx의 전신인 Intercooler.jsλŠ” 경둜 기반 μ˜μ‘΄μ„±μ„ λΌμ΄λΈŒλŸ¬λ¦¬μ— ν†΅ν•©ν–ˆμŠ΅λ‹ˆλ‹€.

htmxλŠ” 이 κΈ°λŠ₯을 κΈ°λ³Έ κΈ°λŠ₯μ—μ„œ μ œμ™Έν–ˆμ§€λ§Œ, path depsλΌλŠ” ν™•μž₯을 톡해 λΉ„μŠ·ν•œ κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€.

ν™•μž₯을 μ‚¬μš©ν•˜λ„λ‘ 예제λ₯Ό μ—…λ°μ΄νŠΈν•˜λ €λ©΄, ν™•μž₯ μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό λ‘œλ“œν•œ λ‹€μŒ λ‹€μŒκ³Ό 같이 HTML을 주석 μ²˜λ¦¬ν•΄μ•Ό ν•©λ‹ˆλ‹€:

<h2>Contacts</h2>
<table class="table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th></th>
    </tr>
  </thead>
  <tbody id="contacts-table" hx-get="/contacts/table" hx-ext="path-deps" hx-trigger="path-deps" path-deps="/contacts">
    ...
  </tbody>
</table>
<h2>Add A Contact</h2>
<form hx-post="/contacts">
  <label>
    Name
        <input name="name" type="text">  
  </label>
  <label>
    Email
        <input name="email" type="email">  
  </label>
</form>

이제 폼이 /contacts URL둜 POSTλ₯Ό ν•  λ•Œ, path-deps ν™•μž₯은 이λ₯Ό κ°μ§€ν•˜μ—¬ μ—°λ½μ²˜ ν…Œμ΄λΈ”μ— path-deps 이벀트λ₯Ό νŠΈλ¦¬κ±°ν•˜μ—¬ μš”μ²­μ„ λ°œμƒμ‹œν‚΅λ‹ˆλ‹€.

이 μ ‘κ·Ό λ°©μ‹μ˜ μž₯점은 응닡 헀더와 κ΄€λ ¨λœ λ³΅μž‘ν•œ 처리λ₯Ό ν”Όν•  수 μžˆλ‹€λŠ” μ μž…λ‹ˆλ‹€. 단점은 μ—°λ½μ²˜κ°€ μ„±κ³΅μ μœΌλ‘œ μƒμ„±λ˜μ§€ μ•Šμ•˜λ”λΌλ„ λͺ¨λ“  POST μš”μ²­μ—μ„œ μš”μ²­μ΄ λ°œμƒν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

#μ–΄λ–€ 방법을 μ‚¬μš©ν•΄μ•Ό ν• κΉŒμš”?

μΌλ°˜μ μœΌλ‘œλŠ” νƒ€κ²Ÿμ„ ν™•μž₯ν•˜λŠ” 첫 번째 μ ‘κ·Ό 방식을 ꢌμž₯ν•©λ‹ˆλ‹€. 특히 μ—…λ°μ΄νŠΈν•΄μ•Ό ν•˜λŠ” μš”μ†Œλ“€μ΄ DOMμ—μ„œ μ„œλ‘œ κ°€κΉŒμ΄ μžˆλŠ” κ²½μš°μ—λŠ” λ”μš± κ·Έλ ‡μŠ΅λ‹ˆλ‹€. 이 방법은 κ°„λ‹¨ν•˜κ³  μ‹ λ’°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

κ·Έ λ‹€μŒμœΌλ‘œλŠ” μ‚¬μš©μž μ •μ˜ μ΄λ²€νŠΈμ™€ OOB μŠ€μ™‘ μ ‘κ·Ό 방식 쀑 ν•˜λ‚˜λ₯Ό 선택할 수 μžˆμŠ΅λ‹ˆλ‹€. μ €λŠ” 이벀트 지ν–₯ μ‹œμŠ€ν…œμ„ μ„ ν˜Έν•˜κΈ° λ•Œλ¬Έμ— μ‚¬μš©μž μ •μ˜ 이벀트 μ ‘κ·Ό 방식을 μ„ ν˜Έν•˜μ§€λ§Œ, μ΄λŠ” 개인적인 μ·¨ν–₯μž…λ‹ˆλ‹€. μ–΄λŠ 것을 μ„ νƒν• μ§€λŠ” 본인의 μ†Œν”„νŠΈμ›¨μ–΄ μ—”μ§€λ‹ˆμ–΄λ§ μ·¨ν–₯κ³Ό μ„œλ²„ μΈ‘ 기술과의 적합성에 따라 κ²°μ •ν•΄μ•Ό ν•©λ‹ˆλ‹€.

λ§ˆμ§€λ§‰μœΌλ‘œ, path-deps μ ‘κ·Ό 방식은 ν₯미둜운 μ ‘κ·Ό λ°©μ‹μœΌλ‘œ, λ§Œμ•½ 이 κ°œλ…μ΄ 본인의 정신적 λͺ¨λΈκ³Ό 전체 μ‹œμŠ€ν…œ μ•„ν‚€ν…μ²˜μ— 잘 λ§žλŠ”λ‹€λ©΄, λͺ…μ‹œμ μΈ μƒˆλ‘œκ³ μΉ¨μ„ ν”Όν•˜λŠ” μž¬λ―ΈμžˆλŠ” 방법이 될 수 μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이 κ°œλ…μ΄ 크게 λŒλ¦¬μ§€ μ•ŠλŠ”λ‹€λ©΄, 이 μ ‘κ·Ό 방식을 λ§ˆμ§€λ§‰μœΌλ‘œ κ³ λ €ν•΄λ³΄μ‹œκΈΈ ꢌμž₯ν•©λ‹ˆλ‹€.