Skip to content

Commit c9d5973

Browse files
committed
Rework connect component based on review notes
Removed use of PureWrapper Used React.memo() on the wrapped component Renamed and extracted makeDerivedPropsSelector Added makeChildElementSelector Simplified render props callback Simplified forwardRef handling
1 parent 259253a commit c9d5973

File tree

1 file changed

+88
-103
lines changed

1 file changed

+88
-103
lines changed

src/components/connectAdvanced.js

Lines changed: 88 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -91,43 +91,6 @@ export default function connectAdvanced(
9191

9292
const displayName = getDisplayName(wrappedComponentName)
9393

94-
let PureWrapper
95-
96-
if (forwardRef) {
97-
class PureWrapperRef extends Component {
98-
shouldComponentUpdate(nextProps) {
99-
return nextProps.derivedProps !== this.props.derivedProps
100-
}
101-
102-
render() {
103-
let { forwardRef, derivedProps } = this.props
104-
return <WrappedComponent {...derivedProps} ref={forwardRef} />
105-
}
106-
}
107-
PureWrapperRef.propTypes = {
108-
//derivedProps: propTypes.object,
109-
forwardRef: propTypes.oneOfType([
110-
propTypes.func,
111-
propTypes.object
112-
])
113-
}
114-
PureWrapper = PureWrapperRef
115-
} else {
116-
class PureWrapperNoRef extends Component {
117-
shouldComponentUpdate(nextProps) {
118-
return nextProps.derivedProps !== this.props.derivedProps
119-
}
120-
121-
render() {
122-
return <WrappedComponent {...this.props.derivedProps} />
123-
}
124-
}
125-
PureWrapperNoRef.propTypes = {
126-
//derivedProps: propTypes.object,
127-
}
128-
PureWrapper = PureWrapperNoRef
129-
}
130-
13194
const selectorFactoryOptions = {
13295
...connectOptions,
13396
getDisplayName,
@@ -140,58 +103,81 @@ export default function connectAdvanced(
140103
WrappedComponent
141104
}
142105

143-
const OuterBase = connectOptions.pure ? PureComponent : Component
106+
const {pure} = connectOptions
144107

145-
class Connect extends OuterBase {
146-
constructor(props) {
147-
super(props)
148-
invariant(forwardRef ? !props.props[storeKey] : !props[storeKey],
149-
'Passing redux store in props has been removed and does not do anything. ' + customStoreWarningMessage
150-
)
151-
this.generatedDerivedProps = this.makeDerivedPropsGenerator()
152-
this.renderWrappedComponent = this.renderWrappedComponent.bind(this)
108+
let OuterBaseComponent = Component
109+
let FinalWrappedComponent = WrappedComponent
110+
111+
if(pure) {
112+
OuterBaseComponent = PureComponent
113+
//FinalWrappedComponent = React.memo(WrappedComponent)
114+
}
115+
116+
class PureWrapper extends Component {
117+
shouldComponentUpdate(nextProps) {
118+
return nextProps.derivedProps !== this.props.derivedProps
153119
}
154120

155-
makeDerivedPropsGenerator() {
156-
let lastProps
157-
let lastState
158-
let lastDerivedProps
159-
let lastStore
160-
let sourceSelector
161-
return (state, props, store) => {
162-
if ((connectOptions.pure && lastProps === props) && (lastState === state)) {
163-
return lastDerivedProps
164-
}
165-
if (store !== lastStore) {
166-
lastStore = store
167-
sourceSelector = selectorFactory(store.dispatch, selectorFactoryOptions)
168-
}
169-
lastProps = props
170-
lastState = state
171-
const nextProps = sourceSelector(state, props)
172-
if (lastDerivedProps === nextProps) {
173-
return lastDerivedProps
174-
}
175-
lastDerivedProps = nextProps
121+
render() {
122+
let { forwardedRef, derivedProps } = this.props
123+
return <WrappedComponent {...derivedProps} ref={forwardedRef} />
124+
}
125+
}
126+
127+
function makeDerivedPropsSelector() {
128+
let lastProps
129+
let lastState
130+
let lastDerivedProps
131+
let lastStore
132+
let sourceSelector
133+
134+
return function selectDerivedProps(state, props, store) {
135+
if ((pure && lastProps === props) && (lastState === state)) {
136+
return lastDerivedProps
137+
}
138+
139+
if (store !== lastStore) {
140+
lastStore = store
141+
sourceSelector = selectorFactory(store.dispatch, selectorFactoryOptions)
142+
}
143+
144+
lastProps = props
145+
lastState = state
146+
147+
const nextProps = sourceSelector(state, props)
148+
149+
if (lastDerivedProps === nextProps) {
176150
return lastDerivedProps
177151
}
152+
153+
lastDerivedProps = nextProps
154+
return lastDerivedProps
178155
}
156+
}
179157

180-
renderWrappedComponentWithRef(value) {
181-
invariant(value,
182-
`Could not find "store" in the context of ` +
183-
`"${displayName}". Either wrap the root component in a <Provider>, ` +
184-
`or pass a custom React context provider to <Provider> and the corresponding ` +
185-
`React context consumer to ${displayName} in connect options.`
186-
)
187-
const { storeState, store } = value
188-
const { forwardRef, props } = this.props
189-
let derivedProps = this.generatedDerivedProps(storeState, props, store)
190-
if (connectOptions.pure) {
191-
return <PureWrapper derivedProps={derivedProps} forwardRef={forwardRef} />
158+
function makeChildElementSelector() {
159+
let lastChildProps, lastForwardRef, lastChildElement
160+
161+
return function selectChildElement(childProps, forwardRef) {
162+
if(childProps !== lastChildProps || forwardRef !== lastForwardRef) {
163+
lastChildProps = childProps
164+
lastForwardRef = forwardRef
165+
lastChildElement = <FinalWrappedComponent {...childProps} ref={forwardRef} />
192166
}
193167

194-
return <WrappedComponent {...derivedProps} ref={forwardRef} />
168+
return lastChildElement
169+
}
170+
}
171+
172+
class Connect extends OuterBaseComponent {
173+
constructor(props) {
174+
super(props)
175+
invariant(forwardRef ? !props.wrapperProps[storeKey] : !props[storeKey],
176+
'Passing redux store in props has been removed and does not do anything. ' + customStoreWarningMessage
177+
)
178+
this.selectDerivedProps = makeDerivedPropsSelector()
179+
this.selectChildElement = makeChildElementSelector()
180+
this.renderWrappedComponent = this.renderWrappedComponent.bind(this)
195181
}
196182

197183
renderWrappedComponent(value) {
@@ -202,12 +188,22 @@ export default function connectAdvanced(
202188
`React context consumer to ${displayName} in connect options.`
203189
)
204190
const { storeState, store } = value
205-
let derivedProps = this.generatedDerivedProps(storeState, this.props, store)
206-
if (connectOptions.pure) {
207-
return <PureWrapper derivedProps={derivedProps} />
191+
192+
let wrapperProps = this.props
193+
let forwardedRef
194+
195+
if(forwardRef) {
196+
wrapperProps = this.props.wrapperProps
197+
forwardedRef = this.props.forwardedRef
208198
}
209199

210-
return <WrappedComponent {...derivedProps} />
200+
let derivedProps = this.selectDerivedProps(storeState, wrapperProps, store)
201+
202+
if(pure) {
203+
return this.selectChildElement(derivedProps, forwardedRef);
204+
}
205+
206+
return <FinalWrappedComponent {...derivedProps} ref={forwardedRef}/>
211207
}
212208

213209
render() {
@@ -221,28 +217,17 @@ export default function connectAdvanced(
221217

222218
Connect.WrappedComponent = WrappedComponent
223219
Connect.displayName = displayName
224-
if (forwardRef) {
225-
Connect.prototype.renderWrappedComponent = Connect.prototype.renderWrappedComponentWithRef
226-
Connect.propTypes = {
227-
props: propTypes.object,
228-
forwardRef: propTypes.oneOfType([
229-
propTypes.func,
230-
propTypes.object
231-
])
232-
}
233-
}
234220

235-
if (!forwardRef) {
236-
return hoistStatics(Connect, WrappedComponent)
237-
}
221+
if (forwardRef) {
222+
const forwarded = React.forwardRef(function forwardConnectRef(props, ref) {
223+
return <Connect wrapperProps={props} forwardedRef={ref} />
224+
})
238225

239-
function forwardRef(props, ref) {
240-
return <Connect props={props} forwardRef={ref} />
226+
forwarded.displayName = displayName
227+
forwarded.WrappedComponent = WrappedComponent
228+
return hoistStatics(forwarded, WrappedComponent)
241229
}
242230

243-
const forwarded = React.forwardRef(forwardRef)
244-
forwarded.displayName = displayName
245-
forwarded.WrappedComponent = WrappedComponent
246-
return hoistStatics(forwarded, WrappedComponent)
231+
return hoistStatics(Connect, WrappedComponent)
247232
}
248233
}

0 commit comments

Comments
 (0)