Skip to content

Commit

Permalink
Release 1.3.4 (#96)
Browse files Browse the repository at this point in the history
* chore: model validate show name

* fix: fix can't get correct state (#95)

* fix: fix can't get correct state

* chore: update version

* fix: fix by the comment

* docs: readonly && get the latest state

Co-authored-by: Hengchang Lu <[email protected]>
  • Loading branch information
alvinhui and luhc228 authored Apr 10, 2020
1 parent 41586a8 commit 8833e97
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 49 deletions.
115 changes: 95 additions & 20 deletions docs/recipes.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,81 @@ For example, the action A in Model A calls the action B in Model B and the actio

Be careful the possibility of endless loop problem will arise when methods from different models call each other.

## Readonly

In some scenarios, you may only want to call the method returned by the model to update the state instead of subscribing to the update of the model state. For example, the button component in the "Basic example", you do not consume the state of the model in the component, so you may not expect the change of the state of the model to trigger the re-rende of the component.

At this time, you can use the `useModelDispatchers` API, check following example:

```js
import store from '@/store';
const { useModelDispatchers } = store;
function Button() {
const [, dispatchers ] = useModel('counter'); // The update of model'state will be subscribed here
const { increment } = dispatchers;
return (
<button type="button" onClick={increment}> + </button>
);
}

function Button() {
const { increment } = useModelDispatchers('counter'); // Updates to model'state will not be subscribed here
return (
<button type="button" onClick={increment}> + </button>
);
}
```

## Get the latest sate of the model

In some scenarios, you may want to get the latest state of the model.

### In Component

```js
import store from '@/store';

function Logger({ foo }) {
// case 1 use state only instead of subscribing to updates(a means of performance optimization)
function doSomeThing() {
const counter = store.getModelState('counter');
alert(counter);
};


// case 2 get the latest state in the closure
const doOhterThing = useCallback(
(payload) => {
const counter = store.getModelState('counter');
alert(counter + foo);
},
[foo]
);

return (
<div>
<button onClick={doSomeThing}>click 1<button>
<button onClick={doOhterThing}>click 2<button>
</div>
);
}
```

### In Model

```js
import store from '@/store';

const user = {
effects: dispatch => ({
async addByAsync(payload, state) {
dispatch.todos.addTodo(payload); // Call methods of other models to update their state
const todos = store.getModelState('todos'); // Get the latest state of the updated model
}
})
}
```

## effects' executing status

`icestore` has built-in support to access the executing status of effects. This enables users to have access to the isLoading and error executing status of effects without defining extra state, making the code more consise and clean.
Expand Down Expand Up @@ -161,26 +236,6 @@ You can use `withModelDispatchers` to call only model actions without listening

See [docs/api](./api.md) for more details.

## Directory organization

For most small and medium-sized projects, it is recommended to centrally manage all the project models in the global `src/models/` directory:

```bash
├── src/
│ ├── components/
│ │ └── NotFound/
│ ├── pages/
│ │ └── Home
│ ├── models/
│ │ ├── modelA.js
│ │ ├── modelB.js
│ │ ├── modelC.js
│ │ └── index.js
│ └── store.js
```

If the project is relatively large, or more likely to follow the page maintenance of the store,then you can declare a store instance in each page directory. However, in this case, cross page store calls should be avoided as much as possible.

## Immutable Description

### Don't destructure the state argument
Expand Down Expand Up @@ -234,6 +289,26 @@ const store = createStore(models, {
});
```

## Directory organization

For most small and medium-sized projects, it is recommended to centrally manage all the project models in the global `src/models/` directory:

```bash
├── src/
│ ├── components/
│ │ └── NotFound/
│ ├── pages/
│ │ └── Home
│ ├── models/
│ │ ├── modelA.js
│ │ ├── modelB.js
│ │ ├── modelC.js
│ │ └── index.js
│ └── store.js
```

If the project is relatively large, or more likely to follow the page maintenance of the store,then you can declare a store instance in each page directory. However, in this case, cross page store calls should be avoided as much as possible.

## Comparison

- O: Yes
Expand Down
116 changes: 96 additions & 20 deletions docs/recipes.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,81 @@ export default createStore({

如果是多个模型间进行相互调用,死循环问题的出现概率就会提升。


## 只调用方法而不订阅更新

在某些场景下,您可能只希望调用模型方法来更新状态而不订阅模型状态的更新。 例如「快速开始」示例中的 Button 组件,您没有在组件中消费模型的状态,因此可能不期望模型状态的变化触发组件的重新渲染。 这时候您可以使用 useModelDispatchers API,看下面的示例比较:

```js
import store from '@/store';

const { useModelDispatchers } = store;
function Button() {
const [, dispatchers ] = useModel('counter'); // 这里会订阅模型状态的更新
const { increment } = dispatchers;
return (
<button type="button" onClick={increment}> + </button>
);
}

function Button() {
const { increment } = useModelDispatchers('counter'); // 这里不会订阅模型状态的更新
return (
<button type="button" onClick={increment}> + </button>
);
}
```

## 获取模型最新状态

在某些场景下,您可能需要获取到模型的最新状态。

### 在组件中

```js
import store from '@/store';

function Logger({ foo }) {
// case 1 只使用状态而不订阅更新(性能优化的手段)
function doSomeThing() {
const counter = store.getModelState('counter');
alert(counter);
};


// case 2 在闭包中获取最新状态
const doOhterThing = useCallback(
(payload) => {
const counter = store.getModelState('counter');
alert(counter + foo);
},
[foo]
);

return (
<div>
<button onClick={doSomeThing}>click 1<button>
<button onClick={doOhterThing}>click 2<button>
</div>
);
}
```

### 在模型中

```js
import store from '@/store';

const user = {
effects: dispatch => ({
async addByAsync(payload, state) {
dispatch.todos.addTodo(payload); // 调用其他模型的方法更新其状态
const todos = store.getModelState('todos'); // 获取更新后的模型最新状态
}
})
}
```

## 模型副作用的执行状态

icestore 内部集成了对于异步副作用的状态记录,方便您在不增加额外的状态的前提下访问异步副作用的执行状态(loading 与 error),从而使状态渲染的处理逻辑更加简洁。
Expand Down Expand Up @@ -159,26 +234,6 @@ export default compose(withModel('user'), withModel('todos'))(TodoList);

查看 [docs/api](./api.zh-CN.md) 了解其使用方式。

## 项目的目录组织

对于大多数中小型项目,建议集中管理模型,例如在 “src/models/” 目录中存放项目的所有模型:

```bash
├── src/
│ ├── components/
│ │ └── NotFound/
│ ├── pages/
│ │ └── Home
│ ├── models/
│ │ ├── modelA.js
│ │ ├── modelB.js
│ │ ├── modelC.js
│ │ └── index.js
│ └── store.js
```

如果项目相对较大,可以按照页面来管理模型。但是,在这种情况下,应该避免跨页面使用模型。

## 可变状态的说明

icestore 默认为 reducer 提供了状态可变的操作方式。
Expand Down Expand Up @@ -231,6 +286,27 @@ const store = createStore(models, {
disableImmer: true; // 👈 通过该配置禁用 immer
});
```

## 项目的目录组织

对于大多数中小型项目,建议集中管理模型,例如在 “src/models/” 目录中存放项目的所有模型:

```bash
├── src/
│ ├── components/
│ │ └── NotFound/
│ ├── pages/
│ │ └── Home
│ ├── models/
│ │ ├── modelA.js
│ │ ├── modelB.js
│ │ ├── modelC.js
│ │ └── index.js
│ └── store.js
```

如果项目相对较大,可以按照页面来管理模型。但是,在这种情况下,应该避免跨页面使用模型。

## 能力对比表

- O: 支持
Expand Down
4 changes: 2 additions & 2 deletions examples/counter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "1.0.0",
"private": true,
"dependencies": {
"@ice/store": "^1.3.3",
"@ice/store": "^1.3.4",
"react": "^16.8.6",
"react-dom": "^16.8.6"
},
Expand Down Expand Up @@ -31,4 +31,4 @@
"last 1 safari version"
]
}
}
}
4 changes: 2 additions & 2 deletions examples/todos/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "1.0.0",
"private": true,
"dependencies": {
"@ice/store": "^1.3.3",
"@ice/store": "^1.3.4",
"lodash": "^4.17.15",
"react": "^16.8.6",
"react-dom": "^16.8.6"
Expand Down Expand Up @@ -33,4 +33,4 @@
"last 1 safari version"
]
}
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ice/store",
"version": "1.3.3",
"version": "1.3.4",
"description": "Simple and friendly state for React",
"main": "lib/index.js",
"files": [
Expand Down Expand Up @@ -64,4 +64,4 @@
"redux": "^4.0.5",
"redux-thunk": "^2.3.0"
}
}
}
4 changes: 2 additions & 2 deletions src/icestore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ export default class Icestore {
[typeof model.name !== 'string', 'model "name" [string] is required'],
[
model.state === undefined && model.baseReducer === undefined,
'model "state" is required',
`model(${model.name}) "state" is required`,
],
[
model.baseReducer !== undefined &&
typeof model.baseReducer !== 'function',
'model "baseReducer" must be a function',
`model(${model.name}) "baseReducer" must be a function`,
],
]);
// run plugin model subscriptions
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/modelApis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default (): T.Plugin => {
}
function useModelState(name: string) {
const selector = store.useSelector(state => state[name]);
if (selector) {
if (typeof selector !== "undefined") {
return selector;
}
throw new Error(`Not found model by namespace: ${name}.`);
Expand Down

0 comments on commit 8833e97

Please sign in to comment.