React: 포털 및 SSR둜 μˆ˜λΆ„ κ³΅κΈ‰μ‹œ μ˜ˆμƒμΉ˜ λͺ»ν•œ κ²½κ³ 

에 λ§Œλ“  2018λ…„ 04μ›” 15일  Β·  24μ½”λ©˜νŠΈ  Β·  좜처: facebook/react

κΈ°λŠ₯ 을 μš”μ²­ν•˜κ±°λ‚˜ 버그λ₯Όλ³΄κ³  ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?

κ³€μΆ©

ν˜„μž¬ 행동은 λ¬΄μ—‡μž…λ‹ˆκΉŒ?

λ‹€μŒ (간체) 슀 λ‹ˆνŽ«μ΄ μ œκ³΅λ©λ‹ˆλ‹€.

class HoverMenu extends React.Component {
  render() {
    if (typeof document === 'undefined') return null
    const root = document.getElementById('root')
    return ReactDOM.createPortal(<div>Hello World</div>, root)
  }
}

class Para extends React.Component {
  render() {
    return (
      <span>
        Some Text
        <HoverMenu />
      </span>
    )
  }
} 

div#root λŠ” μ‘΄μž¬ν•˜λŠ” μœ νš¨ν•œ div 경우 SSR ν›„ μˆ˜ν™”μ‹œ λ‹€μŒ 였λ₯˜κ°€ ν‘œμ‹œλ©λ‹ˆλ‹€.

Warning: Expected server HTML to contain a matching <div> in <span>

HoverMenu 의 μ •μ˜λ₯Ό λ‹€μŒκ³Ό 같이 μ—…λ°μ΄νŠΈν•˜λ©΄ κ²½κ³ κ°€ μ‚¬λΌμ§‘λ‹ˆλ‹€.

class HoverMenu extends React.Component {
  componentDidMount() {
    this.setState({ isActive: true })
  }
  render() {
    const { isActive} = this.state
    if (!isActive) return null
    const root = document.getElementById('root')
    return ReactDOM.createPortal(<div>Hello World</div>, root)
  }
}

setState μ—μ„œ componentDidMount setState 둜 μΈν•œ 이쀑 λ Œλ”λ§ λ•Œλ¬Έμ— κ·Έλ ‡κ²Œν•˜μ§€ μ•ŠλŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” κ·Έ 였λ₯˜κ°€ λ‚˜μ—κ²Œ λ§ν•˜λŠ” 것을 잘 μ΄ν•΄ν•˜μ§€ λͺ»ν•©λ‹ˆλ‹€. μ–΄λ–€ κ²½μš°μ—λ„ <div /> λŠ” μ„œλ²„ μΈ‘μ—μ„œ λ Œλ”λ§λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. HoverMenu DOM div λŠ” DOM span λ‚΄λΆ€μ—μ„œ λ Œλ”λ§λ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ—μ΄ 였λ₯˜λŠ” 특히 ν˜Όλž€ μŠ€λŸ½μŠ΅λ‹ˆλ‹€. ( HoverMenu 이 React span μ•ˆμ— μ€‘μ²©λ˜μ–΄ 있기 λ•Œλ¬Έμ— 이런 일이 λ°œμƒν•˜λŠ”μ§€ κΆκΈˆν•©λ‹ˆλ‹€.)

μ˜ˆμƒλ˜λŠ” λ™μž‘μ€ λ¬΄μ—‡μž…λ‹ˆκΉŒ?

였λ₯˜κ°€ λ°œμƒν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ˜λŠ” 적어도 였λ₯˜ λ©”μ‹œμ§€κ°€ 더 λͺ…ν™•ν•©λ‹ˆλ‹€.

μ–΄λ–€ λ²„μ „μ˜ React와 μ–΄λ–€ λΈŒλΌμš°μ € / OS가이 문제의 영ν–₯을 λ°›μŠ΅λ‹ˆκΉŒ?

크둬 65
λ°˜μ‘ 16.2
(SSRλΆ€ν„° Next 5.1κΉŒμ§€)

medium Bug good first issue

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

μˆ˜λΆ„ 곡급 포털은 μ§€μ›λ˜μ§€ μ•Šμ§€λ§Œ (https://github.com/facebook/react/issues/13097) λ©”μ‹œμ§€ μžμ²΄λŠ” μ˜λ―Έκ°€ μ—†μŠ΅λ‹ˆλ‹€. μ‘°μ‚¬ν•˜κ³  μˆ˜μ •ν•΄μ•Όν•©λ‹ˆλ‹€.

λͺ¨λ“  24 λŒ“κΈ€

setStateλ₯Ό 톡해 ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ λ‹€μ‹œ λ Œλ”λ§ν•˜μ—¬ ν•΄κ²°ν•  μˆ˜λ„μžˆλŠ” λΉ„μŠ·ν•œ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.
제 κ²½μš°μ—λŠ” 포털 λ‚΄λΆ€μ—μ„œ λͺ¨λ‹¬μ„ λ Œλ”λ§ν•˜λ €κ³ ν•©λ‹ˆλ‹€. Modal ꡬ성 μš”μ†ŒλŠ” μ„œλ²„μ—μ„œ λ Œλ”λ§ 될 λ•Œ null λ°˜ν™˜ν•˜κ³  ν΄λΌμ΄μ–ΈνŠΈμ— 포털을 λ§Œλ“­λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ DOM은 μˆ˜ν™” ν›„ μ—‰λ§μ΄λ©λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄ μ£Ό ꡬ성 μš”μ†Œ λ‚΄μ—μ„œ λ‹€μŒκ³Ό 같이 μ‚¬μš©ν•˜λ©΄ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

<Modal>
This is a test
</Modal>

<div className="some-div-after-the-modal">
</div>

μˆ˜ν™” ν›„ 이것을 μ–»λŠ” λŒ€μ‹  :

<!-- Inside the portal container -->
<div class="modal-wrapper">
    <div class="modal-content">This is a test</div>
</div>

<!-- In the main component -->
<div class="some-div-after-the-modal">
</div>

λ‚˜λŠ” 이것을 μ–»λŠ”λ‹€ :

<!-- Inside the portal container -->
<div class="some-div-after-the-modal">
    <div class="modal-content">This is a test</div>
</div>

<!-- In the main component -->
<div class="some-div-after-the-modal">
</div>

그리고 κ²½κ³ λŠ” λ™μΌν•©λ‹ˆλ‹€ ( Expected server HTML to contain a matching <div> in <div> ). μ»€μŠ€ν…€ SSR 방법과 ν•¨κ»˜ React 16.3을 μ‚¬μš©ν•©λ‹ˆλ‹€.

이것이 μ˜λ„ 된 λ™μž‘μΈμ§€ ν™•μ‹€ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μˆ˜λΆ„ 곡급 포털은 μ§€μ›λ˜μ§€ μ•Šμ§€λ§Œ (https://github.com/facebook/react/issues/13097) λ©”μ‹œμ§€ μžμ²΄λŠ” μ˜λ―Έκ°€ μ—†μŠ΅λ‹ˆλ‹€. μ‘°μ‚¬ν•˜κ³  μˆ˜μ •ν•΄μ•Όν•©λ‹ˆλ‹€.

@gaearon μˆ˜μ •μ˜ λͺ©μ μ€

  • [] hydrate ()μ—μ„œ Portal이 μ‚¬μš©λ˜κ³  μžˆμŒμ„ 감지 ν•œ ν›„ λΆˆλ³€μœΌλ‘œ 더 μ μ ˆν•œ 였λ₯˜ λ©”μ‹œμ§€λ₯Ό ν‘œμ‹œν•©λ‹ˆλ‹€.
    예 : invariant violation: Portal is not support on SSR. For more detail, please refer https://github.com/facebook/react/issues/13097
  • [] ν…ŒμŠ€νŠΈ μΆ”κ°€

    • [] Portal이 hydrate ()와 ν•¨κ»˜ μ‚¬μš©λ˜λŠ” 경우 μœ„μ˜ 였λ₯˜ λ©”μ‹œμ§€κ°€ ν‘œμ‹œλ˜μ–΄μ•Όν•©λ‹ˆλ‹€.

ꢌ리?
κΈ‰ν•˜μ§€ μ•Šλ‹€λ©΄ κΈ°κΊΌμ΄ν•©λ‹ˆλ‹€.

SSR Doc μ΄ˆμ•ˆμ„ μ›Ή μ‚¬μ΄νŠΈ μ €μž₯μ†Œλ‘œ κ³„νšν•˜κ³  μžˆμœΌλ―€λ‘œ μˆ˜ν™” λ©”μ»€λ‹ˆμ¦˜μ— μ΅μˆ™ν•΄μ•Όν•©λ‹ˆλ‹€.
이 쑰사가 제 κ³„νšμ— 도움이 될 것 κ°™μŠ΅λ‹ˆλ‹€.
https://github.com/facebook/react/pull/13379

SSRμ—μ„œ 포털이 "아무것도"λ Œλ”λ§λ˜μ§€ μ•ŠλŠ” μ΄μœ λŠ” λ¬΄μ—‡μž…λ‹ˆκΉŒ?

아무것도 λ Œλ”λ§ν•˜λŠ” 것이 μ΅œμ„  인 것 같지 μ•ŠμŠ΅λ‹ˆλ‹€. 포털 μ½˜ν…μΈ λ₯Ό λ‹€λ₯΄κ²Œ λ§Œλ“œλŠ” 것이 μ„œλ²„ λ Œλ”λ§μ˜ κ°€μΉ˜κ°€ μ—†λ‹€κ³  μƒκ°ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μš°λ¦¬λŠ” μ„œμŠ€νŽœμŠ€λ₯Ό μœ„ν•΄ μ„œλ²„ λ Œλ”λŸ¬μ˜ 개편과 ν•¨κ»˜ μ΄κ²ƒμœΌλ‘œ λŒμ•„μ˜¬ κ²ƒμž…λ‹ˆλ‹€.

포털은 κ°œλ…μ μœΌλ‘œ ν΄λΌμ΄μ–ΈνŠΈ μ „μš© ꡬ성 μš”μ†Œμž…λ‹ˆλ‹€. 일반적으둜 μ„œλ²„μ—μ„œ λ Œλ”λ§ ν•˜κ³  싢지 μ•Šμ€ λͺ¨λ‹¬κ³Ό 같은 것에 μ‚¬μš©λ©λ‹ˆλ‹€. λ˜ν•œ dom μš”μ†Œλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. μ΄λŠ” dom이 μ—†κΈ° λ•Œλ¬Έμ— renderToString이 μ‚¬μš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ‚˜λŠ” μ„œλ²„μ—μ„œ κ·Έλ“€κ³Ό ν•¨κ»˜ ν•  μˆ˜μžˆλŠ” μ˜λ―ΈμžˆλŠ” 것이 무엇인지 μ•Œμ§€ λͺ»ν•©λ‹ˆλ‹€. λ˜ν•œ λ˜μ§€λŠ” κ²ƒμ—μ„œ κ°€μΉ˜μžˆλŠ” 것이 보이지 μ•ŠμŠ΅λ‹ˆλ‹€.

λͺ¨λ‹¬κ³Ό 같은 것듀에 μ‚¬μš©

그것은 ν•˜λ‚˜μ˜ μ‚¬μš© μ‚¬λ‘€μ΄μ§€λ§Œ λ°˜λ“œμ‹œ ν΄λΌμ΄μ–ΈνŠΈ μ „μš©μ΄ μ•„λ‹Œ μ‚¬μ΄λ“œ λ°” 및 이와 μœ μ‚¬ν•œ λ‹€λ₯Έ 사둀도 μžˆμŠ΅λ‹ˆλ‹€.

그듀은 λ˜ν•œ dom μš”μ†Œλ₯Ό μ·¨ν•©λ‹ˆλ‹€.

였λ₯Έμͺ½ β€” ν˜„μž¬ λ””μžμΈμ—μ„œ. λ³€κ²½ 될 수 μžˆμŠ΅λ‹ˆλ‹€. https://github.com/facebook/react/pull/8386#issuecomment -262375265

λ‚˜λŠ” λ˜ν•œ λ˜μ§€λŠ” κ²ƒμ—μ„œ κ°€μΉ˜μžˆλŠ” 것을 보지 λͺ»ν•©λ‹ˆλ‹€.

λ˜μ§€κΈ°μ˜ κ°€μΉ˜λŠ” 포털이 μž‘λ™ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 것을 λͺ…μ‹œ 적으둜 μΈμ •ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. {domNode && ReactDOM.createPortal(stuff, domNode)} λ˜λŠ” 이와 μœ μ‚¬ν•œ κ²ƒμœΌλ‘œ μ‰½κ²Œ ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€. DOM λ…Έλ“œλ₯Ό κ°€μ Έμ˜¬ 수 μžˆλŠ”μ§€ μ—¬λΆ€λ₯Ό ν™•μΈν•˜κΈ° μœ„ν•΄ 이미 μ–΄λ–€ μ’…λ₯˜μ˜ 검사λ₯Ό μˆ˜ν–‰ν•΄μ•Όν–ˆκΈ° λ•Œλ¬Έμ—μ΄ μ‹œμ μ—μ„œ 포털을 λ‚΄ 보내지 μ•Šλ„λ‘ 선택할 μˆ˜μžˆλŠ” μΆ©λΆ„ν•œ 데이터가 μžˆμ–΄μ•Όν•©λ‹ˆλ‹€.

이 문제λ₯Ό "쒋은 첫 번째 문제"둜 μˆ˜μ •ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

+1

이 λ¬Έμ œμ— λŒ€ν•΄ μž‘μ—… ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

ν™•μ‹€ν•œ. λ‚˜λŠ” 당신이 ν•  수 μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. κ·Έλž˜μ„œ μ–Όλ§ˆλ‚˜ 멀리 κ°”μŠ΅λ‹ˆκΉŒ? λ‚˜λŠ” μ‹€μ œλ‘œ 그것을 집어 λ“€κΈ°λ₯Ό μƒκ°ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

  • 2

μ•ˆλ…•ν•˜μ„Έμš” μ—¬λŸ¬λΆ„, λ¬Έμ œκ°€μžˆλŠ” νŒŒμΌμ„ μ–΄λ–»κ²Œ 찾을 수 μžˆλŠ”μ§€ μ•Œλ©΄ 도움을받을 수 μžˆμŠ΅λ‹ˆλ‹€.

이 λ¬Έμ œμ— λŒ€ν•œ 뢀뢄적인 pull μš”μ²­μ΄ μžˆμŠ΅λ‹ˆλ‹€.
https://github.com/facebook/react/pull/15473

아직 아무도 μ—†λ‚˜μš”? λ‚˜λŠ” 그것을 받아듀이고 μ‹Άλ‹€.

μ΄κ²ƒμ˜ μƒνƒœλŠ” λ¬΄μ—‡μž…λ‹ˆκΉŒ? μ–΄λ–»κ²Œ μž¬ν˜„ ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

이것이 μ—¬μ „νžˆ λ¬Έμ œμž…λ‹ˆκΉŒ?

이 λ¬Έμ œμ— λŒ€ν•œ 응닡도받지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.

이 문제의 μƒνƒœλŠ” 아직 μ—΄λ € μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

이 문제λ₯Ό 맑을 수 μžˆμŠ΅λ‹ˆκΉŒ?

μ•ˆλ…•ν•˜μ„Έμš”,이 λ¬Έμ œμ— λŒ€ν•΄ μž‘μ—…ν•˜λŠ” μ‚¬λžŒμ΄ μžˆμŠ΅λ‹ˆκΉŒ? 그렇지 μ•Šλ‹€λ©΄ κ°€μ Έ κ°€κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

아무도 μž‘μ—…ν•˜μ§€ μ•ŠμœΌλ©΄

이것이 μ—¬μ „νžˆ λ¬Έμ œμž…λ‹ˆκΉŒ? 그것을 고치렀고 μ‹œλ„ν•œ 것 κ°™μ§€λ§Œ 근본적인 λ¬Έμ œλŠ” μ‹€μ œλ‘œ 일뢀 μ‚¬λžŒλ“€μ΄ 포털이 μ„œλ²„ μΈ‘ λ Œλ”λ§μ—μ„œ μž‘λ™ν•˜κΈ°λ₯Ό μ›ν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. 그렇닀면이 문제λ₯Ό μ’…κ²° ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

div μš”μ†Œλ₯Ό μΆ”κ°€ν•˜λ©΄ μ •μƒμ μœΌλ‘œ μž‘λ™ν•©λ‹ˆλ‹€.

`class Para extends React.Component {
render () {
λ°˜ν™˜ (

일뢀 ν…μŠ€νŠΈ
)

}
}`

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰