Chinese version of hooks view model api
trigkit4 edited this page Nov 23, 2022
·
12 revisions
hooks-view-model是api友好的ui与业务逻辑解耦方案:
- 所有update开头相关的API均为view和viewModel通用的api;
- 所有use开头的api均为view独享api;
- updatexxxState本质是useState的updater
通过key更新全局state
参数:
- key:为了保持key的唯一性,请使用枚举值
- value:要更新的状态值
例子Examples
type GLOBAL_KEYS = {
APP = 'APP'
}
type HeaderVMProps = {
count: number
}
import StoreViewModel from 'hooks-view-model';
import { GLOBAL_KEYS, HeaderVMProps } from './types'
class HeaderViewModel extends StoreViewModel<HeaderVMProps> {
updateCount = (count) => {
this.updateGlobalStateByKey(GLOBAL_KEYS.APP, {
count,
});
};
}
相当于setState:
- 更新当前view的state,view 和 viewModel 适用
- 自动绑定当前viewModel的name作为key,无需传入key
参数:
- value:要更新的状态值
例子Examples
import StoreViewModel from 'hooks-view-model';
class HeaderViewModel extends StoreViewModel<any> {
updatePersonInfo = (person: {
name: string;
age?: number;
height?: number;
}) => {
this.updateCurrentState({
person,
});
};
changeHeaderData = (count) => {
this.updateCurrentState({
headCount: count,
});
};
}
export { HeaderViewModel };
使用immer更新state,可实现细粒度更新:
updateImmerState((draft) => {})
View
import React, { useState, useContext } from 'react';
import { useVM } from 'hooks-view-model';
import { FooterViewModel } from './Footer.ViewModel';
import { GLOBAL_KEYS } from '../GlobalStore';
export default function Footer() {
const {
useCurrentState,
updateTodoValue,
pushNewPerson
} = useVM(FooterViewModel, {});
const {
todo,
persons
} = useCurrentState({
todo: {
title: 'test',
done: true,
},
persons: [
{ name: 'mike', age: 10 },
{ name: 'john', age: 20 },
],
});
console.log('updateImmerState1', todo, persons);
return (
<div style={{ border: '1px solid red' }}>
<button onClick={updateTodoValue}>click updateTodoValue</button>
<button onClick={pushNewPerson}>click pushNewPerson</button>
</div>
);
}
ViewModel
//Footer.ViewModel.ts
import { GLOBAL_KEYS } from '../GlobalStore';
import StoreViewModel from 'hooks-view-model';
class FooterViewModel extends StoreViewModel<any> {
updateTodoValue = () => {
this.updateImmerState(draft => {
draft.todo.done = !draft.todo.done;
});
};
pushNewPerson = () => {
this.updateImmerState(draft => {
draft.persons.push({ name: 'alvin', age: 30 });
});
};
}
export { FooterViewModel };
用法上同,区别是增加了GLOBAL_KEY
updateGlobalTodoValue = () => {
this.updateGlobalImmerState(GLOBAL_KEYS.GLOBAL_TODO, draft => {
draft.global_todo.done = !draft.global_todo.done;
});
};
通过key获取全局state,view和viewModel 适用
获取当前state,view和viewModel 适用
import StoreViewModel from 'hooks-view-model';
class HeaderViewModel extends StoreViewModel<any> {
changeModule = () => {
const { tableData } = this.getCurrentState();
}
}
export { HeaderViewModel };
- 通过key 移除global state,view和viewModel 适用;
-
GlobalState
在组件卸载时不会自动回收,与reducer 或 redux保持一致 -
currentState
在组件卸载时会自动回收
通过keys数组批量获取全局状态值
- 本质是通过new map()实例化的对象,存储在内存中
组件卸载仍会存在,刷新页面或关闭页面,该变量释放
通过key 更新全局变量存储
例子Examples
class FooterViewModel extends StoreViewModel<any> {
updateCount = count => {
this.updateCurrentState({
count,
});
};
updateModalState = () => {
this.updateGlobalStore('modal_close', true);
};
updateLocalValue = () => {
this.updateGlobalPersistStore('local_value', { name: 'huang', age: 123 });
};
removeLocalValue = () => {
const removed = this.removeGlobalPersistStoreByKey('local_value');
console.log('removed', removed);
};
mounted = () => {
console.log('mounted123');
};
}
export { FooterViewModel };
- 通过key获取全局变量存储
- 存在时,返回正确的值;不存在时,返回undefined
- 通过key 移除全局变量存储,返回布尔值
PersistStore 本质是存储在localstorage,localStorage有效期为永久,除非手动删除
更新全局持久化存储
参数:
- key:要更新的键
- value:要更新的值
例子Examples
class FooterViewModel extends StoreViewModel<any> {
updateLocalValue = () => {
this.updateGlobalPersistStore('local_value', { name: 'huang', age: 123 });
};
}
export { FooterViewModel };
通过key获取全局持久化存储的数据
例子Examples
import { useVM } from 'hooks-view-model';
export default function Footer() {
const {
useCurrentState,
getGlobalPersistStoreByKey,
} = useVM(FooterViewModel, {});;
const { count } = useCurrentState({
count: 0,
});
return (
<div style={{ border: '1px solid red' }}>
<p>count: {getGlobalPersistStoreByKey('local_value')}</p>
</div>
);
}
通过key移除全局持久化存储 返回值:布尔值
- true 表示删除成功
- false 表示删除失败
class FooterViewModel extends StoreViewModel<any> {
removeLocalValue = () => {
const removed = this.removeGlobalPersistStoreByKey('local_value');
console.log('removed', removed);
};
}
export { FooterViewModel };
- 类似useState hooks,获取全局 view 对应的state,仅view 适用
- 响应来自updateGlobalStateByKey的更新
参数:
- key:要获取的state对应的key
- initialState:初始化state,类似useState默认值
import { useVM } from 'hooks-view-model';
import { AppViewModel } from './App.ViewModel.ts';
export default function App() {
const {
useGlobalState,
} = useVM(AppViewModel, {});
const { count } = useGlobalState(GLOBAL_KEYS.APP, { count: 0 });
return <div>{count}</div>
}
- hooks,获取当前view 对应的state,仅view 适用
- 响应来自updateCurrentState的更新
参数:
- initialState:初始化state,类似useState默认值
用法:上同
- hooks,实例化ViewModel,view通过调用useVM,可获取对应的ViewModel和StoreViewModel的所有public API;
- 在组件挂载时执行mounted生命周期钩子;在组件卸载时 执行unmounted 生命周期钩子;
- 当props 发生变化时,自动执行onPropsChanged方法
- 将最新的props赋值给viewModel,viewModel 可通过this.props.xxx 获取最新的props
参数:
- viewModel
- props:view传递给viewModel的参数,ViewModel通过this.props访问
import { useVM } from 'hooks-view-model';
export default function Footer() {
const {
updateModalState,
getGlobalStoreByKey,
updateLocalValue,
getGlobalPersistStoreByKey,
removeLocalValue,
useCurrentState
} = useVM(FooterViewModel, {name: 'pefma', value: 'value'});
const { count } = useCurrentState({
count: 0,
});
const [num, setNum] = useState(0);
return (
<div style={{ border: '1px solid red' }}>
<p>count: {count}</p>
<button onClick={() => updateCount(10)}>+</button>
<button onClick={updateModalState}>updateGlobalStore</button>
<button onClick={updateValue}>updateValue</button>
<button onClick={updateLocalValue}>updateLocalValue</button>
<button onClick={removeLocalValue}>removeLocalValue</button>
</div>
);
}
组件挂载的时候,ViewModel 会自动执行该方法,无需在view中引入useEffect
执行相关生命周期api。
mounted相当于是viewModel的componentDidMount
。
mounted的好处就是api简洁,对于async函数的处理有天然的优势,可以对比一下useEffect
hooks和mounted对于异步的处理:
function App() {
useEffect(() => {
(async () => {
await Promise.all([fetchA(), fetchB()])
await postC()
})()
}, [])
return (<div>123</div>)
}
//App.ViewModel.ts
class App extends StoreViewModel {
mounted = async () => {
await Promise.all([fetchA(), fetchB()])
await postC()
}
}
组件卸载的时候,ViewModel 会自动执行该方法
import StoreViewModel from 'hooks-view-model';
class HeaderViewModel extends StoreViewModel<any> {
unmounted = () => {
console.log('app will autorun when component unmounted')
}
}
export { HeaderViewModel };
内置函数,props发生改变时才触发,相当于useDeepCompareEffect
接收新的props时触发,参数:props
// Counter.View.tsx
const Counter = (props: any) => {
// 当传递给CounterViewModel的props发生变化时,onPropsChanged 会自动执行
const { updateCount, useCurrentState } = useVM(CounterViewModel, {
...props,
});
const { count } = useCurrentState({ count: 0 });
return (
<div>
<div>Count is {count}</div>
<button onClick={() => updateCount(count + 1)}>count</button>
<div></div>
</div>
);
};
export { Counter };
// Counter.ViewModel.ts
import StoreViewModel from 'hooks-view-model';
class CounterViewModel extends StoreViewModel<any> {
constructor(props) {
super(props);
}
updateCount = count => {
this.updateCurrentState({
count,
});
};
getCount = () => {
const count = this.getCurrentState();
return count
}
updateModalState = () => {
this.updateGlobalStore('modal_close', true);
};
updateLocalValue = () => {
this.updateGlobalPersistStore('local_value', { name: 'huang', age: 123 });
};
removeLocalValue = () => {
const removed = this.removeGlobalPersistStoreByKey('local_value');
console.log('removed', removed);
};
onPropsChanged = (props: any) => {
console.log('当props 发生变化时自动触发', props);
};
}
export { CounterViewModel };