Skip to content

Commit

Permalink
feat(mobx): 加入mobx支持 (#972)
Browse files Browse the repository at this point in the history
* feat(mobx): 引入mobx

* feat(mobx): 构建&编译支持mobx

* feat(mobx): 文档

* feat(mobx): 解决支付宝小程序全局window或global不存在的问题

* feat(mobx):h5 & RN componentWillUnmount调用时停止监听

* feat(mobx): 版本号与主库保持一致

* feat(mobx): 版本号与主库保持一致(1.1.7)

* feat(mobx): 构建问题修复
  • Loading branch information
nanjingboy authored and luckyadam committed Nov 19, 2018
1 parent 0179a82 commit cfa2978
Show file tree
Hide file tree
Showing 48 changed files with 1,846 additions and 6 deletions.
4 changes: 3 additions & 1 deletion README.md
Expand Up @@ -93,6 +93,8 @@ Taro 立足于微信小程序开发,众所周知小程序的开发体验并不

✅ 支持使用 Redux 进行状态管理。

✅ 支持使用 Mobx 进行状态管理。

✅ 小程序 API 优化,异步 API Promise 化等等。

#### 支持多端开发转化
Expand Down Expand Up @@ -256,4 +258,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.
2 changes: 2 additions & 0 deletions docs/README.md
Expand Up @@ -75,6 +75,8 @@ Taro 立足于微信小程序开发,众所周知小程序的开发体验并不

✅ 支持使用 Redux 进行状态管理

✅ 支持使用 Mobx 进行状态管理

✅ 小程序 API 优化,异步 API Promise 化等等

#### 支持多端开发转化
Expand Down
1 change: 1 addition & 0 deletions docs/SUMMARY.md
Expand Up @@ -135,6 +135,7 @@
* [h5](config-detail.md#h5)
* [异步编程](async-await.md)
* [使用 Redux](redux.md)
* [使用 Mobx](mobx.md)
* [使用微信小程序第三方组件](wx-third-party.md)
* [Taro 代码与微信小程序代码混写](wx-hybrid.md)
* [技术原理](principle.md)
Expand Down
190 changes: 190 additions & 0 deletions docs/mobx.md
@@ -0,0 +1,190 @@
---
title: 使用 Mobx
---

[Mobx](https://mobx.js.org/) 为复杂项目中状态管理提供了一种简单高效的机制;Taro 提供了 `@tarojs/mobx` 来让开发人员在使用Mobx的过程中获得更加良好的开发体验。

> 下文中示例代码均在 [taro-mobx-sample](https://github.com/nanjingboy/taro-mobx-sample)
首先请安装 `mobx``@tarojs/mobx``@tarojs/mobx-h5``@tarojs/mobx-rn`

```bash
$ yarn add mobx @tarojs/mobx @tarojs/mobx-h5 @tarojs/mobx-rn
# 或者使用 npm
$ npm install --save mobx @tarojs/mobx @tarojs/mobx-h5 @tarojs/mobx-rn
```

随后可以在项目 `src` 目录下新增一个 `store/counter.js` 文件

```jsx
// src/store/counter.js
import { observable } from 'mobx'

const counterStore = observable({
counter: 0
})

counterStore.increment = function () {
this.counter++
}

counterStore.decrement = function() {
this.counter--
}

counterStore.incrementAsync = function() {
setTimeout(() => {
this.counter++
}, 1000);
}

export default counterStore
```

接下来在项目入口文件 `app.js` 中使用 `@tarojs/mobx` 中提供的 `Provider` 组件将前面写好的 `store` 接入应用中

```jsx
// src/app.jsimport Taro, { Component } from '@tarojs/taro'
import { Provider } from '@tarojs/mobx'
import Index from './pages/index'

import counterStore from './store/counter'

import './app.scss'

const store = {
counterStore
}

class App extends Component {

config = {
pages: [
'pages/index/index'
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#fff',
navigationBarTitleText: 'WeChat',
navigationBarTextStyle: 'black'
}
}

componentDidMount () {}

componentDidShow () {}

componentDidHide () {}

componentDidCatchError () {}

render () {
return (
<Provider store={store}>
<Index />
</Provider>
)
}
}

Taro.render(<App />, document.getElementById('app'))

```

然后,我们在页面中可通过 `@tarojs/mobx` 提供的 `inject` 以及 `observer` 方法将 `mobx` 与我们的页面进行关联

```jsx
// src/pages/index/index.js
import Taro, { Component } from '@tarojs/taro'
import { View, Button, Text } from '@tarojs/components'
import { observer, inject } from '@tarojs/mobx'

import './index.scss'

@inject('counterStore')
@observer
class Index extends Component {

config = {
navigationBarTitleText: '首页'
}

componentWillMount () { }

componentWillReact () {
console.log('componentWillRect')
}

componentDidMount () { }

componentWillUnmount () { }

componentDidShow () { }

componentDidHide () { }

increment = () => {
const { counterStore } = this.props
counterStore.increment()
}

decrement = () => {
const { counterStore } = this.props
counterStore.decrement()
}

incrementAsync = () => {
const { counterStore } = this.props
counterStore.incrementAsync()
}

render () {
const { counterStore } = this.props
return (
<View className='index'>
<Button onClick={this.increment}>+</Button>
<Button onClick={this.decrement}>-</Button>
<Button onClick={this.incrementAsync}>Add Async</Button>
<Text>{counterStore.counter}</Text>
</View>
)
}
}

export default Index

```

上例中 `Provider``inject``observer`的使用方式基本上与[mobx-react](https://github.com/mobxjs/mobx-react) 保持了一致,但也有以下几点需要注意:

* `Provider`不支持嵌套,即全局只能存在一个`Provider`
*`mobx-react`中,可通过以下方式设置`store`

```jsx
<Provider store1={xxxx} store2={xxxx}>
<XXX />
</Provider>
```

而在`@tarojs/mobx`中,我们需要使用以下方式设置:

```jsx
const store = {
store1: xxxx,
store2: xxxx
}
<Provider store={store}>
<XXX />
</Provider>
```

* `inject``observer` 不能在stateless组件上使用
* `observer` 不支持任何参数
* 按照以下方式使用 `inject` 时,不能省略`observer`的显式调用:

```jsx
@inject((stores, props) => ({
counterStore: stores.counterStore
}))
@observer //这个不能省略
```
4 changes: 4 additions & 0 deletions lerna.json
Expand Up @@ -32,6 +32,10 @@
"packages/taro-transformer-wx",
"packages/postcss-pxtransform",
"packages/babel-plugin-transform-jsx-to-stylesheet",
"packages/taro-mobx",
"packages/taro-mobx-common",
"packages/taro-mobx-h5",
"packages/taro-mobx-rn",
"packages/taro-with-weapp",
"packages/taroize"
],
Expand Down
17 changes: 16 additions & 1 deletion packages/taro-cli/src/h5.js
Expand Up @@ -20,6 +20,8 @@ const PACKAGES = {
'@tarojs/taro-h5': '@tarojs/taro-h5',
'@tarojs/redux': '@tarojs/redux',
'@tarojs/redux-h5': '@tarojs/redux-h5',
'@tarojs/mobx': '@tarojs/mobx',
'@tarojs/mobx-h5': '@tarojs/mobx-h5',
'@tarojs/router': '@tarojs/router',
'@tarojs/components': '@tarojs/components',
'nervjs': 'nervjs',
Expand Down Expand Up @@ -187,7 +189,7 @@ function processEntry (code, filePath) {

/* 插入<Provider /> */
if (providerComponentName && storeName) {
// 使用redux
// 使用redux 或 mobx
funcBody = `
<${providorImportName} store={${storeName}}>
${funcBody}
Expand Down Expand Up @@ -368,6 +370,17 @@ function processEntry (code, filePath) {
specifiers.push(t.importSpecifier(t.identifier(providerComponentName), t.identifier(providerComponentName)))
}
source.value = PACKAGES['@tarojs/redux-h5']
} else if (value === PACKAGES['@tarojs/mobx']) {
const specifier = specifiers.find(item => {
return t.isImportSpecifier(item) && item.imported.name === providerComponentName
})
if (specifier) {
providorImportName = specifier.local.name
} else {
providorImportName = providerComponentName
specifiers.push(t.importSpecifier(t.identifier(providerComponentName), t.identifier(providerComponentName)))
}
source.value = PACKAGES['@tarojs/mobx-h5']
}
}
},
Expand Down Expand Up @@ -571,6 +584,8 @@ function processOthers (code, filePath) {
}
} else if (value === PACKAGES['@tarojs/redux']) {
source.value = PACKAGES['@tarojs/redux-h5']
} else if (value === PACKAGES['@tarojs/mobx']) {
source.value = PACKAGES['@tarojs/mobx-h5']
}
}
},
Expand Down
3 changes: 3 additions & 0 deletions packages/taro-cli/src/project.js
Expand Up @@ -122,6 +122,9 @@ class Project extends Creator {
}, {
name: 'Redux 模板',
value: 'redux'
}, {
name: 'Mobx 模板',
value: 'mobx'
}]

if (typeof conf.template !== 'string') {
Expand Down
17 changes: 15 additions & 2 deletions packages/taro-cli/src/rn/transformJS.js
Expand Up @@ -36,7 +36,9 @@ const PACKAGES = {
'@tarojs/components-rn': '@tarojs/components-rn',
'react': 'react',
'react-native': 'react-native',
'react-redux-rn': '@tarojs/taro-redux-rn'
'react-redux-rn': '@tarojs/taro-redux-rn',
'@tarojs/mobx': '@tarojs/mobx',
'@tarojs/mobx-rn': '@tarojs/mobx-rn'
}

function getInitPxTransformNode (projectConfig) {
Expand Down Expand Up @@ -275,6 +277,17 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) {
specifiers.push(t.importSpecifier(t.identifier(providerComponentName), t.identifier(providerComponentName)))
}
source.value = PACKAGES['react-redux-rn']
} else if (value === PACKAGES['@tarojs/mobx']) {
const specifier = specifiers.find(item => {
return t.isImportSpecifier(item) && item.imported.name === providerComponentName
})
if (specifier) {
providorImportName = specifier.local.name
} else {
providorImportName = providerComponentName
specifiers.push(t.importSpecifier(t.identifier(providerComponentName), t.identifier(providerComponentName)))
}
source.value = PACKAGES['@tarojs/mobx-rn']
} else if (value === PACKAGES['@tarojs/components']) {
source.value = PACKAGES['@tarojs/components-rn']
}
Expand Down Expand Up @@ -334,7 +347,7 @@ function parseJSCode ({code, filePath, isEntryFile, projectConfig}) {
funcBody = `<RootStack/>`
}
if (providerComponentName && storeName) {
// 使用redux
// 使用redux 或 mobx
funcBody = `
<${providorImportName} store={${storeName}}>
${funcBody}
Expand Down
7 changes: 7 additions & 0 deletions packages/taro-cli/src/util/resolve_npm_files.js
Expand Up @@ -216,6 +216,13 @@ function npmCodeHack (filePath, content, buildAdapter) {
content = content.replace(/Function\([\'"]return this[\'"]\)\(\)/, 'this')
}
break
case 'mobx.js':
//解决支付宝小程序全局window或global不存在的问题
content = content.replace(
/typeof window\s{0,}!==\s{0,}[\'"]undefined[\'"]\s{0,}\?\s{0,}window\s{0,}:\s{0,}global/,
'typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {}'
)
break
case '_html.js':
content = 'module.exports = false;'
break
Expand Down

0 comments on commit cfa2978

Please sign in to comment.