-
Notifications
You must be signed in to change notification settings - Fork 132
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(wx-react-redux): wx-react-redux 基于react-redux重新实现
- Loading branch information
1 parent
22783e1
commit 7d55920
Showing
13 changed files
with
473 additions
and
176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
## wx-react-redux | ||
|
||
The code is a copy from [react-redux](https://github.com/reduxjs/react-redux). We made some adjustments for Wechat |
This file was deleted.
Oops, something went wrong.
18 changes: 18 additions & 0 deletions
18
packages/wx-react-redux/miniprogram_dist/components/Provider.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { Component } from '@areslabs/wx-react' | ||
|
||
export default class Provider extends Component { | ||
getChildContext() { | ||
return { store: this.store } | ||
} | ||
|
||
constructor(props, context) { | ||
super(props, context) | ||
this.store = props.store | ||
} | ||
|
||
render() {} | ||
} | ||
|
||
Provider.childContextTypes = { | ||
store: {} | ||
} |
324 changes: 324 additions & 0 deletions
324
packages/wx-react-redux/miniprogram_dist/components/connect.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,324 @@ | ||
import { HocComponent, createElement } from '@areslabs/wx-react' | ||
import shallowEqual from '../utils/shallowEqual' | ||
import wrapActionCreators from '../utils/wrapActionCreators' | ||
import warning from '../utils/warning' | ||
import isPlainObject from '../utils/isPlainObject' | ||
import hoistStatics from '../utils/hoistNonReactStatics' | ||
|
||
const defaultMapStateToProps = state => ({}) // eslint-disable-line no-unused-vars | ||
const defaultMapDispatchToProps = dispatch => ({ dispatch }) | ||
const defaultMergeProps = (stateProps, dispatchProps, parentProps) => ({ | ||
...parentProps, | ||
...stateProps, | ||
...dispatchProps | ||
}) | ||
|
||
function getDisplayName(WrappedComponent) { | ||
return WrappedComponent.displayName || WrappedComponent.name || 'Component' | ||
} | ||
|
||
let errorObject = { value: null } | ||
function tryCatch(fn, ctx) { | ||
try { | ||
return fn.apply(ctx) | ||
} catch (e) { | ||
errorObject.value = e | ||
return errorObject | ||
} | ||
} | ||
|
||
// Helps track hot reloading. | ||
let nextVersion = 0 | ||
|
||
export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) { | ||
const shouldSubscribe = Boolean(mapStateToProps) | ||
const mapState = mapStateToProps || defaultMapStateToProps | ||
|
||
let mapDispatch | ||
if (typeof mapDispatchToProps === 'function') { | ||
mapDispatch = mapDispatchToProps | ||
} else if (!mapDispatchToProps) { | ||
mapDispatch = defaultMapDispatchToProps | ||
} else { | ||
mapDispatch = wrapActionCreators(mapDispatchToProps) | ||
} | ||
|
||
const finalMergeProps = mergeProps || defaultMergeProps | ||
const { pure = true, withRef = false } = options | ||
const checkMergedEquals = pure && finalMergeProps !== defaultMergeProps | ||
|
||
return function wrapWithConnect(WrappedComponent) { | ||
const connectDisplayName = `Connect(${getDisplayName(WrappedComponent)})` | ||
|
||
function checkStateShape(props, methodName) { | ||
if (!isPlainObject(props)) { | ||
warning( | ||
`${methodName}() in ${connectDisplayName} must return a plain object. ` + | ||
`Instead received ${props}.` | ||
) | ||
} | ||
} | ||
|
||
function computeMergedProps(stateProps, dispatchProps, parentProps) { | ||
const mergedProps = finalMergeProps(stateProps, dispatchProps, parentProps) | ||
return mergedProps | ||
} | ||
|
||
class Connect extends HocComponent { | ||
shouldComponentUpdate() { | ||
return !pure || this.haveOwnPropsChanged || this.hasStoreStateChanged | ||
} | ||
|
||
constructor(props, context) { | ||
super(props, context) | ||
this.store = props.store || context.store | ||
|
||
const storeState = this.store.getState() | ||
this.state = { storeState } | ||
this.clearCache() | ||
} | ||
|
||
computeStateProps(store, props) { | ||
if (!this.finalMapStateToProps) { | ||
return this.configureFinalMapState(store, props) | ||
} | ||
|
||
const state = store.getState() | ||
const stateProps = this.doStatePropsDependOnOwnProps ? | ||
this.finalMapStateToProps(state, props) : | ||
this.finalMapStateToProps(state) | ||
|
||
return stateProps | ||
} | ||
|
||
configureFinalMapState(store, props) { | ||
const mappedState = mapState(store.getState(), props) | ||
const isFactory = typeof mappedState === 'function' | ||
|
||
this.finalMapStateToProps = isFactory ? mappedState : mapState | ||
this.doStatePropsDependOnOwnProps = this.finalMapStateToProps.length !== 1 | ||
|
||
if (isFactory) { | ||
return this.computeStateProps(store, props) | ||
} | ||
|
||
return mappedState | ||
} | ||
|
||
computeDispatchProps(store, props) { | ||
if (!this.finalMapDispatchToProps) { | ||
return this.configureFinalMapDispatch(store, props) | ||
} | ||
|
||
const { dispatch } = store | ||
const dispatchProps = this.doDispatchPropsDependOnOwnProps ? | ||
this.finalMapDispatchToProps(dispatch, props) : | ||
this.finalMapDispatchToProps(dispatch) | ||
|
||
return dispatchProps | ||
} | ||
|
||
configureFinalMapDispatch(store, props) { | ||
const mappedDispatch = mapDispatch(store.dispatch, props) | ||
const isFactory = typeof mappedDispatch === 'function' | ||
|
||
this.finalMapDispatchToProps = isFactory ? mappedDispatch : mapDispatch | ||
this.doDispatchPropsDependOnOwnProps = this.finalMapDispatchToProps.length !== 1 | ||
|
||
if (isFactory) { | ||
return this.computeDispatchProps(store, props) | ||
} | ||
|
||
return mappedDispatch | ||
} | ||
|
||
updateStatePropsIfNeeded() { | ||
const nextStateProps = this.computeStateProps(this.store, this.props) | ||
if (this.stateProps && shallowEqual(nextStateProps, this.stateProps)) { | ||
return false | ||
} | ||
|
||
this.stateProps = nextStateProps | ||
return true | ||
} | ||
|
||
updateDispatchPropsIfNeeded() { | ||
const nextDispatchProps = this.computeDispatchProps(this.store, this.props) | ||
if (this.dispatchProps && shallowEqual(nextDispatchProps, this.dispatchProps)) { | ||
return false | ||
} | ||
|
||
this.dispatchProps = nextDispatchProps | ||
return true | ||
} | ||
|
||
updateMergedPropsIfNeeded() { | ||
const nextMergedProps = computeMergedProps(this.stateProps, this.dispatchProps, this.props) | ||
if (this.mergedProps && checkMergedEquals && shallowEqual(nextMergedProps, this.mergedProps)) { | ||
return false | ||
} | ||
|
||
this.mergedProps = nextMergedProps | ||
return true | ||
} | ||
|
||
isSubscribed() { | ||
return typeof this.unsubscribe === 'function' | ||
} | ||
|
||
trySubscribe() { | ||
if (shouldSubscribe && !this.unsubscribe) { | ||
this.unsubscribe = this.store.subscribe(this.handleChange.bind(this)) | ||
this.handleChange() | ||
} | ||
} | ||
|
||
tryUnsubscribe() { | ||
if (this.unsubscribe) { | ||
this.unsubscribe() | ||
this.unsubscribe = null | ||
} | ||
} | ||
|
||
componentDidMount() { | ||
this.trySubscribe() | ||
} | ||
|
||
componentWillReceiveProps(nextProps) { | ||
if (!pure || !shallowEqual(nextProps, this.props)) { | ||
this.haveOwnPropsChanged = true | ||
} | ||
} | ||
|
||
componentWillUnmount() { | ||
this.tryUnsubscribe() | ||
this.clearCache() | ||
} | ||
|
||
clearCache() { | ||
this.dispatchProps = null | ||
this.stateProps = null | ||
this.mergedProps = null | ||
this.haveOwnPropsChanged = true | ||
this.hasStoreStateChanged = true | ||
this.haveStatePropsBeenPrecalculated = false | ||
this.statePropsPrecalculationError = null | ||
this.renderedElement = null | ||
this.finalMapDispatchToProps = null | ||
this.finalMapStateToProps = null | ||
} | ||
|
||
handleChange() { | ||
if (!this.unsubscribe) { | ||
return | ||
} | ||
|
||
const storeState = this.store.getState() | ||
const prevStoreState = this.state.storeState | ||
if (pure && prevStoreState === storeState) { | ||
return | ||
} | ||
|
||
if (pure && !this.doStatePropsDependOnOwnProps) { | ||
const haveStatePropsChanged = tryCatch(this.updateStatePropsIfNeeded, this) | ||
if (!haveStatePropsChanged) { | ||
return | ||
} | ||
if (haveStatePropsChanged === errorObject) { | ||
this.statePropsPrecalculationError = errorObject.value | ||
} | ||
this.haveStatePropsBeenPrecalculated = true | ||
} | ||
|
||
this.hasStoreStateChanged = true | ||
this.setState({ storeState }) | ||
} | ||
|
||
getWrappedInstance() { | ||
return this.wrappedInstance | ||
} | ||
|
||
render() { | ||
const { | ||
haveOwnPropsChanged, | ||
hasStoreStateChanged, | ||
haveStatePropsBeenPrecalculated, | ||
statePropsPrecalculationError, | ||
renderedElement | ||
} = this | ||
|
||
this.haveOwnPropsChanged = false | ||
this.hasStoreStateChanged = false | ||
this.haveStatePropsBeenPrecalculated = false | ||
this.statePropsPrecalculationError = null | ||
|
||
if (statePropsPrecalculationError) { | ||
throw statePropsPrecalculationError | ||
} | ||
|
||
let shouldUpdateStateProps = true | ||
let shouldUpdateDispatchProps = true | ||
if (pure && renderedElement) { | ||
shouldUpdateStateProps = hasStoreStateChanged || ( | ||
haveOwnPropsChanged && this.doStatePropsDependOnOwnProps | ||
) | ||
shouldUpdateDispatchProps = | ||
haveOwnPropsChanged && this.doDispatchPropsDependOnOwnProps | ||
} | ||
|
||
let haveStatePropsChanged = false | ||
let haveDispatchPropsChanged = false | ||
if (haveStatePropsBeenPrecalculated) { | ||
haveStatePropsChanged = true | ||
} else if (shouldUpdateStateProps) { | ||
haveStatePropsChanged = this.updateStatePropsIfNeeded() | ||
} | ||
if (shouldUpdateDispatchProps) { | ||
haveDispatchPropsChanged = this.updateDispatchPropsIfNeeded() | ||
} | ||
|
||
let haveMergedPropsChanged = true | ||
if ( | ||
haveStatePropsChanged || | ||
haveDispatchPropsChanged || | ||
haveOwnPropsChanged | ||
) { | ||
haveMergedPropsChanged = this.updateMergedPropsIfNeeded() | ||
} else { | ||
haveMergedPropsChanged = false | ||
} | ||
|
||
if (!haveMergedPropsChanged && renderedElement) { | ||
return renderedElement | ||
} | ||
|
||
if (withRef) { | ||
this.renderedElement = createElement(WrappedComponent, { | ||
...this.mergedProps, | ||
...this.hocProps, | ||
ref: (wrappedInstance) => { | ||
this.wrappedInstance = wrappedInstance | ||
} | ||
}) | ||
} else { | ||
this.renderedElement = createElement(WrappedComponent, { | ||
...this.mergedProps, | ||
...this.hocProps, | ||
}) | ||
} | ||
|
||
|
||
|
||
return this.renderedElement | ||
} | ||
} | ||
|
||
Connect.displayName = connectDisplayName | ||
Connect.WrappedComponent = WrappedComponent | ||
Connect.contextTypes = { | ||
store: {} | ||
} | ||
|
||
return hoistStatics(Connect, WrappedComponent) | ||
} | ||
} |
Oops, something went wrong.