@heygrady/

createActionDispatchers

ES6

convenience function to optionally create a mapDispatchToPropsFactory that only compares specific propNames

fork
loading
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
const filterProps = (props, onlyPropNames = []) => onlyPropNames.reduce((newProps, propName) => {
  newProps[propName] = props[propName]
  return newProps
}, {})

const shouldFactoryBindProps = (prevProps, nextProps, comparePropNames = []) => {
  if (prevProps === undefined || (prevProps !== undefined && nextProps === undefined)) { return true }
  return comparePropNames.some(propName => prevProps[propName] !== nextProps[propName])
}
  
const createDispatchPropsFactory = (createDispatchProps, comparePropNames = []) => {
  let prevOwnProps
  let dispatchProps
  return () => {
    return (dispatch, ownProps) => {
      const shouldBind = shouldFactoryBindProps(prevOwnProps, ownProps, comparePropNames)
      if (shouldBind) {
        console.log('--> binding action creators!')
        dispatchProps = createDispatchProps(dispatch, ownProps)
        prevOwnProps = filterProps(ownProps, comparePropNames)
      }
      return dispatchProps
    }
  }
}

const createActionDispatchers = (createDispatchProps, comparePropNames = []) => {
  const argsLength = createDispatchProps.length
  const bindOwnProps = argsLength === 2
  const shouldCreateFactory = !!comparePropNames.length
  if (bindOwnProps && shouldCreateFactory) {
    return createDispatchPropsFactory(createDispatchProps, comparePropNames)
  }
  return createDispatchProps
}

// --- test setup

const describe = (label, func) => {
  console.log(`-- ${label} --`)
  func()
  console.log('\n')
}

const GOOSE_HONK = 'GOOSE_HONK'
const honk = (id) => ({ type: GOOSE_HONK, payload: id })

const dispatch = (action) => console.log(action) // <-- fake dispatch
const props = {
  label: 'something',
  id: 123
}

// --- tests

describe('with factory', () => {
  const mapStateToProps = createActionDispatchers((dispatch, ownProps) => ({
    onClick: () => dispatch(honk(ownProps.id))
  }), ['id'])
  
  let dispatchProps
  
  // initializing connect
  const createDispatchProps = mapStateToProps(dispatch, props) // <-- connect does this  on init
  
  dispatchProps = createDispatchProps(dispatch, props) // <-- connect does this on init; whenever props change
  
  // first, initial props
  dispatchProps.onClick()
  
  // second, change unrelated prop
  console.log('change label')
  props.label = 'something else'
  dispatchProps = createDispatchProps(dispatch, props)
  dispatchProps.onClick()
  
  // third, change interesting prop
  console.log('change id')
  props.id = 234
  dispatchProps = createDispatchProps(dispatch, props)
  dispatchProps.onClick()
  
  console.log('bound only two times!')
})

describe('without factory', () => {
  props.id = 123
  
  const mapStateToProps = createActionDispatchers((dispatch, ownProps) => {
    console.log('--> binding action creators!')
    return {
      onClick: () => dispatch(honk(ownProps.id))
    }
  })
  let dispatchProps
  
  // initializing connect
  dispatchProps = mapStateToProps(dispatch, props) // <-- connect does this  on init; whenever props change
  
  // first, initial props
  dispatchProps.onClick()
  
  // second, change unrelated prop
  console.log('change label')
  props.label = 'something else'
  dispatchProps = mapStateToProps(dispatch, props)
  dispatchProps.onClick()
  
  // third, change interesting prop
  console.log('change id')
  props.id = 234
  dispatchProps = mapStateToProps(dispatch, props)
  dispatchProps.onClick()
  
  console.log('bound all three times :(')
})

describe('without ownProps', () => {
  const mapStateToProps = createActionDispatchers((dispatch) => {
    console.log('--> binding action creators!')
    return {
      onClick: () => dispatch(honk())
    }
  })
  let dispatchProps
  
  // initializing connect
  dispatchProps = mapStateToProps(dispatch, props) // <-- connect does this  on init only
  
  // first, initial props
  dispatchProps.onClick()
  
  // second, change unrelated prop
  console.log('change label')
  props.label = 'something else'
  dispatchProps.onClick()
  
  // third, change interesting prop
  console.log('change id')
  props.id = 234
  dispatchProps.onClick()
  
  console.log('bound only once!')
})

Babel Compiler v6.4.4 Copyright (c) 2014-2015 Sebastian McKenzie