Redux: μ—°κ²°λœ ꡬ성 μš”μ†Œκ°€ 쀑첩 된 μ—°κ²°λœ ꡬ성 μš”μ†Œ ν…ŒμŠ€νŠΈ

에 λ§Œλ“  2016λ…„ 11μ›” 10일  Β·  21μ½”λ©˜νŠΈ  Β·  좜처: reduxjs/redux

μ•ˆλ…•ν•˜μ„Έμš”, 이것은 문제 λΌκΈ°λ³΄λ‹€λŠ” μ§ˆλ¬Έμ— κ°€κΉμŠ΅λ‹ˆλ‹€.

μ΅œκ·Όμ— ν”„λ‘œμ νŠΈμ— React와 Reduxλ₯Ό μ‚¬μš©ν•˜κΈ° μ‹œμž‘ν–ˆκ³  ν…ŒμŠ€νŠΈμ— λͺ‡ 가지 λ¬Έμ œκ°€ μžˆμ§€λ§Œ λ¬Έμ„œκ°€ λ¬Έμ œμ— λŒ€ν•œ 결정적인 해결책을 μ œκ³΅ν•˜μ§€ μ•ŠλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

ν˜„μž¬ λ‚˜λŠ” 일뢀 λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•˜κ³  싢은 μ—°κ²°λœ ꡬ성 μš”μ†Œκ°€ μžˆμ§€λ§Œ 첫 번째 ꡬ성 μš”μ†Œ 내에 쀑첩 된 μ—°κ²°λœ ꡬ성 μš”μ†Œκ°€ 있으며 κ²°κ΅­ μ†Œν’ˆ λ˜λŠ” μƒνƒœ (λ˜λŠ” λŒ€λΆ€λΆ„μ˜ 경우 λ‘˜ λ‹€)에 μ˜ν•΄ μ°¨λ‹¨λ˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. 쀑첩 된 ꡬ성 μš”μ†Œκ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

ν…ŒμŠ€νŠΈν•˜λ €λŠ” ꡬ성 μš”μ†Œμ—λ§Œ 집쀑할 수 μžˆλ„λ‘ ν•˜λ‚˜μ˜ ꡬ성 μš”μ†Œλ₯Ό μŠ€ν„° λΉ™ν•˜λŠ” 방법이 μžˆλŠ”μ§€ κΆκΈˆν•©λ‹ˆλ‹€.

미리 κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€

question

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

μ—¬κΈ°μ„œ μ œκΈ°λ˜λŠ” λ¬Έμ œλŠ” ν…ŒμŠ€νŠΈμ€‘μΈ ꡬ성 μš”μ†Œκ°€ 직접 ν•˜μœ„ λ˜λŠ” 계측 μ•„λž˜ μ–΄λ”˜κ°€μ— λ‹€λ₯Έ μ—°κ²°λœ ꡬ성 μš”μ†Œλ₯Ό λ Œλ”λ§ ν•  λ•Œμž…λ‹ˆλ‹€. mount() λ₯Ό 톡해 전체 λ Œλ”λ§μ„ μˆ˜ν–‰ν•˜λ©΄ ν•˜μœ„ μ—°κ²° ꡬ성 μš”μ†Œκ°€ μ ˆλŒ€μ μœΌλ‘œ this.context.store μ•‘μ„ΈμŠ€λ₯Ό μ‹œλ„ν•˜μ§€λ§Œ 찾지 λͺ»ν•©λ‹ˆλ‹€. λ”°λΌμ„œ μ£Όμš” μ˜΅μ…˜μ€ 얕은 ν…ŒμŠ€νŠΈλ₯Ό μˆ˜ν–‰ν•˜μ—¬ ν•˜μœ„ ν•­λͺ©μ΄ λ Œλ”λ§λ˜μ§€ μ•Šλ„λ‘ν•˜κ±°λ‚˜ μ‹€μ œλ‘œ μ»¨ν…μŠ€νŠΈμ—μ„œ μ €μž₯μ†Œλ₯Ό μ‚¬μš©ν•  수 μžˆλ„λ‘ λ§Œλ“œλŠ” κ²ƒμž…λ‹ˆλ‹€.

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

두가지:

1) 이것은 μ‚¬μš©λ²•μ΄λ©° μ•„λ§ˆλ„ μŠ€νƒ μ˜€λ²„ν”Œλ‘œλ‘œ μ΄λ™ν•΄μ•Όν•©λ‹ˆλ‹€.

2) connect μƒμœ„ ꡬ성 μš”μ†Œ μ‚¬μš© 편의의 일뢀
unconnected ꡬ성 μš”μ†Œμ— λŒ€ν•œ λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•˜κ³ 
reduxλ₯Ό μ‹ λ’°ν•˜μ—¬ 맀μž₯ μ£Όλ³€μ˜ 배관을 μ²˜λ¦¬ν•΄μ•Όν•©λ‹ˆλ‹€.

λ‚΄κ°€ μ˜λ―Έν•˜λŠ” λ°”κ°€ λͺ…ν™•ν•˜μ§€ μ•ŠμœΌλ©΄ 예제λ₯Ό κ²Œμ‹œ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λͺ‡ 가지 생각 :

  • ν•˜λ‚˜μ˜ ꡬ성 μš”μ†Œμ—λ§Œ μ§‘μ€‘ν•˜λŠ” ν•œ 가지 방법은 μ‹€μ œλ‘œ μžμ‹μ„ λ Œλ”λ§ν•˜μ§€ μ•ŠλŠ” "얕은"λ Œλ”λ§μ„ μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
  • ν…ŒμŠ€νŠΈμ—μ„œ <Provider store={testStore}><ConnectedComponent /></Provider> 을 λ Œλ”λ§ ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

참고둜 μ—¬κΈ° React / Redux ν…ŒμŠ€νŠΈμ— λŒ€ν•œ μ—¬λŸ¬ 기사에 λŒ€ν•œ 링크가 μžˆμŠ΅λ‹ˆλ‹€. 도움이 될 수 μžˆμŠ΅λ‹ˆλ‹€ :

그리고 예, μ‚¬μš©λ²• μ§ˆλ¬ΈμœΌλ‘œμ„œ 이것은 λ‹€λ₯Έ κ³³μ—μ„œ μ‹€μ œλ‘œ 더 잘 μ§ˆλ¬Έλ©λ‹ˆλ‹€.

κ°μ‚¬ν•©λ‹ˆλ‹€ @markerikson μ €λŠ” ν˜„μž¬ μ–ΈκΈ‰ ν•œ ν›„μžμ˜ 방법을 μ‹œλ„ν•˜κ³  μžˆμ§€λ§Œ 링크 λͺ©λ‘λ„ 뢁마크 ν•  κ²ƒμž…λ‹ˆλ‹€. :)

ν•œ 번 ꡬ성 μš”μ†Œλ₯Ό λΆ„λ¦¬ν•˜μ—¬ ν…ŒμŠ€νŠΈν•˜λ €λ©΄ μ—¬μ „νžˆ λ‹€μŒκ³Ό 같은 μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

// Component.js
import React from 'react'

export const Component = ({ a, b, c }) => ( 
  // ...
)

// ...

export default connect(mapStateToProps, mapDispatchToProps)(Component)

그런 λ‹€μŒ ν…ŒμŠ€νŠΈμ—μ„œ μ—°κ²°λ˜κΈ° 전에 ꡬ성 μš”μ†Œλ₯Ό κ°€μ Έμ˜¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

// Component.spec.js
import { Component } from './Component.js'
import { mount } from 'enzyme'

it('should mount without exploding', () => {
  mount(<Component a={1} b={2} c={3} />)
})

μ •λ§λ‘œ ν…ŒμŠ€νŠΈν•˜κ³  싢은 것이 Provider λ₯Ό λ Œλ”λ§ν•˜λŠ” 것이 합리적이라고 μƒκ°ν•˜λŠ” 것보닀 μƒμ μ˜ λ³€κ²½ 사항이 μ˜¬λ°”λ₯΄κ²Œ μ „νŒŒλ˜κ³  μžˆλ‹€λŠ” 것이며, ν…ŒμŠ€νŠΈμ—μ„œ λ§Žμ€ κ°€μΉ˜λ₯Ό μ–»μ—ˆλŠ”μ§€ ν™•μ‹€ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ—¬κΈ°μ„œ μ œκΈ°λ˜λŠ” λ¬Έμ œλŠ” ν…ŒμŠ€νŠΈμ€‘μΈ ꡬ성 μš”μ†Œκ°€ 직접 ν•˜μœ„ λ˜λŠ” 계측 μ•„λž˜ μ–΄λ”˜κ°€μ— λ‹€λ₯Έ μ—°κ²°λœ ꡬ성 μš”μ†Œλ₯Ό λ Œλ”λ§ ν•  λ•Œμž…λ‹ˆλ‹€. mount() λ₯Ό 톡해 전체 λ Œλ”λ§μ„ μˆ˜ν–‰ν•˜λ©΄ ν•˜μœ„ μ—°κ²° ꡬ성 μš”μ†Œκ°€ μ ˆλŒ€μ μœΌλ‘œ this.context.store μ•‘μ„ΈμŠ€λ₯Ό μ‹œλ„ν•˜μ§€λ§Œ 찾지 λͺ»ν•©λ‹ˆλ‹€. λ”°λΌμ„œ μ£Όμš” μ˜΅μ…˜μ€ 얕은 ν…ŒμŠ€νŠΈλ₯Ό μˆ˜ν–‰ν•˜μ—¬ ν•˜μœ„ ν•­λͺ©μ΄ λ Œλ”λ§λ˜μ§€ μ•Šλ„λ‘ν•˜κ±°λ‚˜ μ‹€μ œλ‘œ μ»¨ν…μŠ€νŠΈμ—μ„œ μ €μž₯μ†Œλ₯Ό μ‚¬μš©ν•  수 μžˆλ„λ‘ λ§Œλ“œλŠ” κ²ƒμž…λ‹ˆλ‹€.

@markerikson μ•„ μ’‹μ•„, λ‚˜λŠ” OPκ°€ μ™ΈλΆ€κ°€ μ•„λ‹Œ λ‚΄λΆ€ ꡬ성 μš”μ†Œλ₯Ό ν…ŒμŠ€νŠΈν•˜λ €κ³ ν•œλ‹€κ³  μƒκ°ν–ˆλ‹€λŠ” 것을 λ‹€μ‹œ μ½μ—ˆμŠ΅λ‹ˆλ‹€. πŸ‘

μ§€κΈˆκΉŒμ§€ 도와 μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€.

ν˜„μž¬ λ‚΄κ°€ κ²ͺκ³ μžˆλŠ” μ£Όμš” λ¬Έμ œλŠ” 내뢀에 쀑첩 된 μ—°κ²°λœ ꡬ성 μš”μ†Œμ— μƒνƒœλ₯Ό 전달할 수 μ—†μ–΄ λ·°κ°€ μ˜¬λ°”λ₯΄κ²Œ λ Œλ”λ§λ˜μ§€ μ•ŠλŠ”λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

일반적으둜 μ‘°λ‘± μƒνƒœλŠ” μ œκ°€ μ‹€μ œλ‘œ κ½€ 고심 ν•΄ μ™”μœΌλ©° μ£Όμ œμ— λŒ€ν•΄ 결정적인 것을 찾을 수 μ—†μ—ˆκΈ° λ•Œλ¬Έμ— λˆ„κ΅°κ°€ μ‘°λ‘± μƒνƒœλ₯Ό 쀑첩 된 μ—°κ²° λ˜λŠ” μƒμœ„ ꡬ성 μš”μ†Œ?

TIA

@StlthyLee : "톡과 μƒνƒœ"λž€ 무엇을 μ˜λ―Έν•©λ‹ˆκΉŒ? ν…ŒμŠ€νŠΈμ—μ„œ <Provider store={store}><ComponentWithConnectedDescendants /></Provider> λ₯Ό λ Œλ”λ§ν•˜λ©΄ μž‘μ—…μ΄ μ²˜λ¦¬λ©λ‹ˆλ‹€.

λ¬Έμ œλŠ” μ˜¬λ°”λ₯΄κ²Œ μ²˜λ¦¬ν•˜μ§€ μ•ŠλŠ” κ²ƒμž…λ‹ˆλ‹€. κ·Έ μ•ˆμ— 쀑첩 된 ꡬ성 μš”μ†Œμ—λŠ” ν˜„μž¬ μ–΄λ–€ 이유둜 인해 얻지 λͺ»ν•˜λŠ” μ‘μš© ν”„λ‘œκ·Έλž¨ μƒνƒœμ˜ νŠΉμ • 맀개 λ³€μˆ˜κ°€ ν•„μš”ν•©λ‹ˆλ‹€.

@StlthyLeeλŠ” μ•„λ§ˆλ„ 예제 / μš”μ  / codepen / repo-link λ˜λŠ” 무언가λ₯Ό λ„£μ–΄μ•Ό ν•  κ²ƒμž…λ‹ˆλ‹€. 여기에 μš©μ–΄ μΆ©λŒμ΄μžˆλŠ” κ²ƒμ²˜λŸΌ 보이기 λ•Œλ¬Έμ— 문제λ₯Ό λ°œκ²¬ν•˜λŠ” 데 μ‹œκ°„μ΄ 덜 κ±Έλ¦½λ‹ˆλ‹€.

@Koleok 희망적으둜 이것은 λͺ…ν™•ν•˜κ²Œ 도움이 될 κ²ƒμž…λ‹ˆλ‹€

https://gist.github.com/StlthyLee/02e116d945867a77c382fa0105af1bf3

그렇지 μ•Šλ‹€λ©΄ λ¬Όμ–΄λ³΄μ‹­μ‹œμ˜€. 이것이 μ œκ°€ λ°‘λ°”λ‹₯에 λ„λ‹¬ν•˜κ³  싢은 κ²ƒμž…λ‹ˆλ‹€. μ§€λ‚œ 9-10 λ…„ λ™μ•ˆ Rails μ„Έκ³„μ—μ„œ μΌν•˜κ³  κ·Έ κ΄€μ μ—μ„œ TDD에 λŒ€ν•΄ 잘 μ΄ν•΄ν•˜κ³  μžˆμ—ˆκΈ° λ•Œλ¬Έμ— μ €λŠ” 이제 React / Redux μ„Έκ³„μ—μ„œ TDD에 λŒ€ν•œ λ‚΄ 머리.

κ·Έλž˜μ„œ μ €λŠ” μ§€κΈˆμ΄ 문제의 λ°‘λ°”λ‹₯에 λ„λ‹¬ν–ˆλ‹€κ³  λ―ΏμŠ΅λ‹ˆλ‹€. 그것은 ν…ŒμŠ€νŠΈ λ¬Έμ œκ°€ μ•„λ‹ˆλΌ λ‹€λ₯Έ νŒ€μ›μ΄ λ§Œλ“  카피와 과거의 였λ₯˜μ˜€μŠ΅λ‹ˆλ‹€. μ„ ν˜Έν•˜λŠ” TDD λ°©μ‹λ³΄λ‹€λŠ” μ½”λ“œμ— 맞게 ν…ŒμŠ€νŠΈν•©λ‹ˆλ‹€. 여기에 제곡된 λͺ¨λ“  정보에 κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€.

일뢀 μ‚¬μš© μ‚¬λ‘€μ—μ„œ μž‘λ™ ν•  μˆ˜μžˆλŠ” 또 λ‹€λ₯Έ μ˜΅μ…˜μ„ μ œκ³΅ν•˜κΈ° μœ„ν•΄ μ΅œκ·Όμ— 쀑첩 된 μ—°κ²° ꡬ성 μš”μ†Œμ—μ„œμ΄ λ¬Έμ œκ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. λͺ¨μ˜ μ €μž₯μ†Œλ₯Ό λ§Œλ“œλŠ” λŒ€μ‹  각 ꡬ성 μš”μ†Œμ˜ μ—°κ²°λ˜μ§€ μ•Šμ€ 버전을 내보내 μ €μž₯μ†Œμ—†μ΄ λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό μˆ˜ν–‰ν–ˆμŠ΅λ‹ˆλ‹€. 이 같은:

class TopLevelImpl extends React.PureComponent {
  // Implementation goes here
}

// Export here for unit testing.  The unit test imports privates and uses TopLevel
// with Enzyme's mount().
export const privates = {
  TopLevel: TopLevelImpl,
}

export const TopLevel = connect(mapStateToProps)(TopLevelImpl)

μžμ‹ 쀑첩 ꡬ성 μš”μ†Œμ— λŒ€ν•΄ λ™μΌν•œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜μ—¬ 각 ꡬ성 μš”μ†Œλ₯Ό λ…λ¦½μ μœΌλ‘œ ν…ŒμŠ€νŠΈ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

그런 λ‹€μŒ μ΅œμƒμœ„ μ—°κ²° ꡬ성 μš”μ†Œλ₯Ό κ°€μ Έ μ™€μ„œ μ•±μ˜ render() ν•¨μˆ˜μ—μ„œ μ†Œν’ˆμœΌλ‘œ μžμ‹ μ—°κ²° ꡬ성 μš”μ†Œλ₯Ό μ „λ‹¬ν–ˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μ΅œμƒμœ„ ꡬ성 μš”μ†Œλ₯Ό λ‹¨μœ„ ν…ŒμŠ€νŠΈ ν•  λ•Œ μ—°κ²°λœ ꡬ성 μš”μ†Œλ₯Ό μ „λ‹¬ν•˜λŠ” λŒ€μ‹  λͺ¨μ˜ ꡬ성 μš”μ†Œλ₯Ό μ „λ‹¬ν•˜μ—¬ μ˜¬λ°”λ₯Έ μœ„μΉ˜μ— λ Œλ”λ§λ˜λŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μ—°κ²°λ˜μ§€ μ•Šμ€ ꡬ성 μš”μ†Œλ₯Ό 전달할 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

이 같은:

// Root render function
render() {
  return (
    <Provider store={store}>
      <TopLevel child1={<Child1 />} child2={<Child2 />} />
    </Provider>
  )
}

λ‚˜λŠ” μ‹€μ œλ‘œ λ‹Ήμ‹ μ˜ 아이디어λ₯Ό μ’‹μ•„ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ λŒ€μ‹  μ΄λ ‡κ²Œ ν•΄μš”

const props = {
  child1: () => (<div />),
  child2: () => (<div />)
}
<TopLevel {...props} />

이미 child1κ³Ό child2λ₯Ό ν…ŒμŠ€νŠΈν–ˆλ‹€λ©΄ TopLevel ꡬ성 μš”μ†Œμ— 포함 ν•  ν•„μš”κ°€ 없을 κ²ƒμž…λ‹ˆλ‹€.

ꡬ성 μš”μ†Œλ₯Ό μ‘°κ±΄λΆ€λ‘œ λ Œλ”λ§ν•΄μ•Όν•˜λŠ” κ²½μš°μ—λ„ ν•¨μˆ˜λ₯Ό μ „λ‹¬ν•©λ‹ˆλ‹€.

λ‚˜λŠ” λ‹Ήμ‹ μ˜ λ§ˆμ§€λ§‰ λ¬Έμž₯을 λ”°λ₯΄μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν…ŒμŠ€νŠΈλŠ” ν•˜μœ„ ꡬ성 μš”μ†Œλ₯Ό λ‹€λ₯Έ ꡬ성 μš”μ†Œλ‘œ μ „λ‹¬ν•˜λŠ” 것과 μ–΄λ–€ 관련이 μžˆμŠ΅λ‹ˆκΉŒ?

잘. 예λ₯Ό λ“€μ–΄ ν•˜λ‚˜ λ˜λŠ” λͺ‡ 개의 λ‚΄λΆ€ μ—°κ²° ꡬ성 μš”μ†Œ λ₯Ό μ‚¬μš©ν•˜λŠ” μš”μ†Œκ°€ μžˆμŠ΅λ‹ˆλ‹€. 이 경우 μ™ΈλΆ€ ꡬ성 μš”μ†Œλ₯Ό ν…ŒμŠ€νŠΈν•˜λ €λ©΄ λ‹€μŒκ³Ό 같이 μˆ˜ν–‰ν•©λ‹ˆλ‹€.

wrapper = mount(<ExternalComponent.WrappedComponent {...props} />)

κ·ΈλŸ¬λ‚˜ λ‚΄λΆ€ ꡬ성 μš”μ†Œ κ°€ μ œλŒ€λ‘œ μ‹€ν–‰ ν•„μš”ν•˜λ‹€λŠ” 였λ₯˜ κ°€ μžˆμŠ΅λ‹ˆλ‹€.

Invariant Violation: Could not find "store" in either the context or props

그런 λ‹€μŒ λͺ¨μ˜ μƒνƒœ 등을 μ „λ‹¬ν•˜λ €κ³ ν–ˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 제 κ²½μš°μ—λŠ” 비동기 호좜, initialState 등을 ν¬ν•¨ν•˜μ—¬ μ—°κ²°λœ λͺ¨λ“  ꡬ성 μš”μ†Œμ— λŒ€ν•΄ λ§Žμ€ μ΄ˆκΈ°ν™”λ₯Ό μˆ˜ν–‰ν•΄μ•Όν•˜λ©° 이와 κ΄€λ ¨λœ λ‹€λ₯Έ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.

μ™ΈλΆ€ ꡬ성 μš”μ†Œλ₯Ό ν…ŒμŠ€νŠΈν•˜κ³  μ‹Άλ‹€λ©΄ λͺ¨λ“  λ‚΄λΆ€ μ—°κ²°λœ ꡬ성 μš”μ†Œμ— λŒ€ν•΄ λͺ¨λ“  μ μ ˆν•œ μ΄ˆκΈ°ν™”λ₯Ό μˆ˜ν–‰ν•˜λŠ” 것이 κ³Όμž‰μ΄λΌκ³  μƒκ°ν•©λ‹ˆλ‹€.

κ·Έλž˜μ„œ μ €λŠ” μ—°κ²°λœ λͺ¨λ“  μ»΄ν¬λ„ŒνŠΈ λ₯Ό μ™ΈλΆ€λ‘œ 빈 div 둜

였 예, 그것은 νŒ¨ν„΄μ— λŒ€ν•œ μ›λž˜μ˜ λ™κΈ°μ˜€μŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ λ¬Έμž₯을 μˆ˜μ •ν•˜λ €λ©΄ "이미 child1 및 child2λ₯Ό ν…ŒμŠ€νŠΈν–ˆλ‹€λ©΄ λ‹¨μœ„ ν…ŒμŠ€νŠΈμ‹œ TopLevel ꡬ성 μš”μ†Œμ— 전달할 ν•„μš”κ°€ μ—†λ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€."λΌλŠ” μ˜λ―Έμž…λ‹ˆλ‹€.

λ™μ˜ν•©λ‹ˆλ‹€.

@StlthyLee , λΆˆν–‰νžˆλ„ μ—°κ²°λœ ꡬ성 μš”μ†Œκ°€ 쀑첩 된 ꡬ성 μš”μ†Œλ₯Ό ν…ŒμŠ€νŠΈν•˜λ €κ³  ν•  λ•Œ λ™μΌν•œ λ¬Έμ œμ— μ§λ©΄ν–ˆμŠ΅λ‹ˆλ‹€.

특히 μœ μš©ν•œ 해결책은 ν…ŒμŠ€νŠΈ ν™˜κ²½μ— 따라 쀑첩 된 ꡬ성 μš”μ†Œλ₯Ό redux μ €μž₯μ†Œμ— μ—°κ²°ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

  • ν…ŒμŠ€νŠΈκ°€ μ‹€ν–‰λ˜λ©΄ ν™˜κ²½ λ³€μˆ˜ NODE_ENV="test" ν•©λ‹ˆλ‹€. 이 λ³€μˆ˜λ₯Ό ν¬μ°©ν•˜κ³  ꡬ성 μš”μ†Œκ°€ κΈ°λ³Έ 속성을 받도둝 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이 경우 ꡬ성 μš”μ†Œκ°€ μ €μž₯μ†Œμ— μ—°κ²°λ˜μ–΄ μžˆμ§€ μ•ŠμœΌλ©° μƒμœ„ ꡬ성 μš”μ†Œλ₯Ό ν…ŒμŠ€νŠΈ ν•  λ•Œ λ¬Έμ œκ°€ λ‚˜νƒ€λ‚˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  • λ‹€λ₯Έ κ²½μš°μ—λŠ” ꡬ성 μš”μ†Œλ₯Ό μ—°κ²°ν•˜μ‹­μ‹œμ˜€. μ΄λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ ꡬ성 μš”μ†Œλ₯Ό μ‹€ν–‰ν•  λ•Œμ˜ κΈ°λ³Έ μ‹œλ‚˜λ¦¬μ˜€μž…λ‹ˆλ‹€.

a) λ¨Όμ € ν™˜κ²½μ΄ test 인지 ν™•μΈν•˜λŠ” λ„μš°λ―Έ ν•¨μˆ˜κ°€ ν•„μš”ν•©λ‹ˆλ‹€.

export default function ifTestEnv(forTestEnv, forNonTestEnv) {
  const isTestEnv = process && process.env && process.env.NODE_ENV === 'test';
  const hoc = isTestEnv ? forTestEnv : forNonTestEnv;
  return function(component) {
    return hoc(component);
  };
}

b) λ‹€μŒμœΌλ‘œ defaultProps() 및 connect() λŠ” ν™˜κ²½μ— 따라 μ‘°κ±΄λΆ€λ‘œ μ μš©λ˜μ–΄μ•Όν•©λ‹ˆλ‹€.

import React, { Component } from 'react';
import { connect } from 'react-redux';
import defaultProps from 'recompose/defaultProps';

import ifTestEnv from 'helpers/if_test_env';
import { fetch } from './actions';

class MyComponent extends Component {
   render() {
      const { propA, propB } = this.props;
      return <div>{propA} {probB}</div>
   }

   componentDidMount() {
      this.props.fetch();
   }
}

function mapStateToProps(state) {
  return {
    propA: state.valueA,
    propB: state.valueB
  };
}

export default ifTestEnv(
  defaultProps({
    propA: 'defaultA',
    propB: 'defaultB',
    fetch() {   }
  }),
  connect(mapStateToProps, { fetch })
)(MyComponent);

c) ν…ŒμŠ€νŠΈλ₯Ό μ‹€ν–‰ν•  λ•Œ NODE_ENV 이 "test" ν™•μΈν•©λ‹ˆλ‹€.

  • mocha CLIλ₯Ό μ‚¬μš©ν•  λ•Œ ν…ŒμŠ€νŠΈ ν™˜κ²½μ„ μ„€μ •ν•˜κΈ° μœ„ν•΄ NODE_ENV='test' mocha app/**/*.test.jsx 접두사λ₯Ό μž…λ ₯ν•©λ‹ˆλ‹€.
  • webpack의 경우 ν”ŒλŸ¬κ·ΈμΈμ„ μ μš©ν•˜μ‹­μ‹œμ˜€.
plugins: [
    // plugins...
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('test')
      },
    })
]

@markerikson 두 가지 μ œμ•ˆμ— κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€. 두 번째λ₯Ό μ‹œλ„ν•˜κ³  Provider둜 ν…ŒμŠ€νŠΈν•˜κΈ° μœ„ν•΄ ꡬ성 μš”μ†Œλ₯Ό λž˜ν•‘ν–ˆμŠ΅λ‹ˆλ‹€. 이 경우 mapStateToProps λŠ” μ œλŒ€λ‘œ μž‘λ™ν•˜μ§€λ§Œ mapDispatchToProps μ˜ˆμƒλ˜λŠ” κ²°κ³Όλ₯Ό 얻지 λͺ»ν•©λ‹ˆλ‹€. μ—¬κΈ°μ„œ ν…ŒμŠ€νŠΈμ€‘μΈ ꡬ성 μš”μ†ŒλŠ” λ‹€λ₯Έ μ—°κ²°λœ ꡬ성 μš”μ†Œλ₯Ό λ Œλ”λ§ν•©λ‹ˆλ‹€.

λ‚΄ mapDispatchToPropsλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

/* <strong i="10">@flow</strong> */
import { bindActionCreators } from 'redux';

import type { Dispatch } from './types';
import * as actions from './actions';

export default (dispatch: Dispatch, ownProps: Object): Object => ({
  actions: bindActionCreators(actions, dispatch),
});

μ—¬κΈ°μ„œ λ°˜ν™˜ 된 μž‘μ—…μ˜ 값은 undefined μž…λ‹ˆλ‹€.

store.js

import { applyMiddleware, compose, createStore } from 'redux';
import { autoRehydrate } from 'redux-persist';
import thunk from 'redux-thunk';

import rootReducer from './reducers';
import { REHYDRATE } from 'redux-persist/constants';

const store = compose(autoRehydrate(), applyMiddleware(thunk, createActionBuffer(REHYDRATE)))(createStore)(rootReducer);

export default store;

λ‚˜λŠ” 이것이 κ½€ 였래된 μŠ€λ ˆλ“œλΌλŠ” 것을 μ•Œκ³  μžˆμ§€λ§Œ 이것이 μ•½κ°„ μ„±κ°€μ‹  λ¬Έμ œλΌλŠ” 것을 μ•Œμ•˜κ³ μ΄ μ†”λ£¨μ…˜μ΄ (λ‚˜μ™€ 같은)이 μŠ€λ ˆλ“œλ₯Ό μš°μ—°νžˆ λ°œκ²¬ν•˜λŠ” μ‚¬λžŒμ—κ²Œ 도움이 될 것이라고 μƒκ°ν–ˆμŠ΅λ‹ˆλ‹€.

μ‹€μ œλ‘œ Redux와 κ΄€λ ¨λœ 것을 ν…ŒμŠ€νŠΈν•˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— λ‚΄κ°€ 찾은 κ°„λ‹¨ν•œ 해결책은 전달 된 λ³€κ²½λ˜μ§€ μ•Šμ€ ꡬ성 μš”μ†Œ 만 λ°˜ν™˜ν•˜λ„λ‘ μ—°κ²° ν•¨μˆ˜λ₯Ό μ‘°λ‘±ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄ μ‘μš© ν”„λ‘œκ·Έλž¨μ— λ‹€μŒκ³Ό 같은 ꡬ성 μš”μ†Œκ°€μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

export class ExampleApp extends Component {
  render() {
  }
}

export default connect(
  null,
  { someAction }
)(ExampleApp);

그런 λ‹€μŒ ν…ŒμŠ€νŠΈ 파일의 μ‹œμž‘ 뢀뢄에 λͺ¨μ˜ μ—°κ²° ν•¨μˆ˜λ₯Ό λ°°μΉ˜ν•˜μ—¬ Reduxκ°€ ꡬ성 μš”μ†Œμ™€ μƒν˜Έ μž‘μš©ν•˜λŠ” 것을 쀑지 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

jest.mock("react-redux", () => {
  return {
    connect: (mapStateToProps, mapDispatchToProps) => (
      ReactComponent
    ) => ReactComponent
  };
});

이 쑰둱은 μ—°κ²°λœ μžμ‹μ„ λ§ˆμš΄νŠΈν•˜λŠ” λͺ¨λ“  ν…ŒμŠ€νŠΈ νŒŒμΌμ— λ°°μΉ˜ν•΄μ•Όν•©λ‹ˆλ‹€.

@scottbanyard μ–΄λ–»κ²Œ μ†Œν’ˆμ„ μžμ‹ ꡬ성 μš”μ†Œμ— μ „λ‹¬ν•©λ‹ˆκΉŒ?

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