六月底因为前司经济性裁员,10天内疯狂面试拿到好几个offer(外包字节、外包学而思和一些不知名的小公司),果然是树挪死人挪活,最后选择了还不错的公司,新公司主要是做机器人软件和云端管理软件的,前景还算可以。随后会整理最近的面经(已经在整理中了,是React方向),敬请期待。
新公司主要的技术栈是React+Typescript+carbonDesign+Mobx+GraphGL+Jest+nuxtjs,相较于上司,有很多需要扩展的知识点。
今天主要介绍下Mobx。
欢迎关注我的公众号:萌萌哒草头将军
Mobx是响应式状态管理库,无关任何前端框架。现在已经发布到Mobx6了。在Mobx5之前,响应式原理是基于Object.defineProperty
的,可以向下兼容到ES5浏览器,而从Mobx5开始使用proxy
特性支持响应式,最低支持ES6浏览器。
相较于Redux,Mobx只强调下面三个概念
一句话概括:在任何事件中调用action,修改state,如果这个state是响应式的,那么会通知基于这个state派生的计算值,或者触发派生的副作用。
其中派生属性可以分为两种情况
通过Mobx定义一个响应式的Store有很多种方法,在不同的方法中定义他们也有所不同。
类的写法虽然笨重,但是适合模块化开发,易于扩展和维护。
import { makeObservable, observable, action, runInAction } from "mobx";
class MyStore {
let tableList = [];
let condition = {
current: 1,
pageSize: 10,
// ...other
};
constructer () {
constructor(title) {
makeObservable(this, {
tableList: observable,
condition: observable,
getTableList: action,
onConditionChangez: action
})
// 设置 reaction,当 condition 变化时自动请求 tableList 数据
reaction(
() => this.condition, // 监听的表达式
(condition) => this.getTableList(condition) // 触发的副作用
)
// 初始化时默认请求列表数据
this.getTableList(this.condition);
}
// 计算属性
get getInBeijing() {
return this.tableList.map(item => item.address === "beijing");
}
getTableList (condition) {
fetch("/v1/table/list", {
method: "post",
data: condition
}).then((res) => {
runInAction(() => {
this.tableList = res.data.list;
})
})
}
onConditionChange (condition) {
this.condition = condition;
}
}
}
使用接口创建对象的写法通常和组件结合在一起使用,虽然灵活,但是由于太过零散,不易于扩展。
import { observable, action } from "mobx"
funtion App () {
const myStore = observable({
tableList: [],
condition: {
pageSize: 10,
current: 1,
// ...other
},
// 计算属性
get getInBeijing() {
return this.tableList.map(item => item.address === "beijing");
}
})
// 副作用
reaction(
() => myStore.condition,
() => getTableList()
};
const getTableList = action(() => {
fetch("/v1/table/list", {
method: "post",
data: myStore.condition
}).then((res) => {
runInAction(() => {
myStore.tableList = res.data.list;
})
})
})
const onConditionChange = action(myStore) => {
myStore.condition = condition
}
useEffect(() => {
myStore.getTableList(myStore.condition);
}, [])
return <>
<Condition condition={myState.condtion} onChange={onConditionChange} />
<Table data={myState.tableList} onPaigionChange={onConditionChange} />
</>
}
关于副作用,除了上面使用的reaction
方法还有autorun
和when
。具体的使用如下:
reaction(
() => this.condition, // 监听的表达式
(condition) => this.getTableList(condition) // 触发的副作用
)
when(
() => !this.condition,
() => console.log("数据为空")
)
// 当when方法没有设置第二个参数时,会返回Promise对象
when(() => !this.condition).then(() => {
console.log("数据为空");
})
autorun(() => this.getTableList(this.condition))
另外记得,这些副作用都会返回销毁监听的方法,例如,在React使用Mobx时,通常我们会在组件销毁时清除他们
useEffect(() => {
const dispose = reaction(
() => this.condition, // 监听的表达式
(condition) => this.getTableList(condition) // 触发的副作用
)
// return () => disopose()
return dispose
}, [])
但是在实际的开发中,我们会使用具体的和框架相关的Mobx,mobx-react、mobx-vue。这样的好处是和组件结合的更紧密,而且不用每次都指定销毁方法。
在React中使用Mobx,通常有两个包:mobx-react、mobx-react-lite
在react的写法也有很多种,下面是几种常见的写法(我们依然使用上面的MyStore类)
const myStore = new Mystore()
const StoreContext = createContext(myStore);
const App = observer(() => {
const myState = useContext(StoreContext)
return <>
<Condition condition={myState.condtion} onChange={myState.onConditionChange} />
<Table data={myState.tableList} onPaigionChange={myState.onConditionChange} />
</>
})
ReactDOM.render(
<StoreContext.Provider value={myStore}>
<App />
</StoreContext.Provider>,
document.body
)
const App = observer(() => {
const [state] = useState(() => new Mystore())
return <>
<Condition condition={myState.condtion} onChange={state.onConditionChange} />
<Table data={myState.tableList} onPaigionChange={state.onConditionChange} />
</>
})
ReactDOM.render(<App />, document.body)
useLocalObservable
钩子useLocalObservable钩子可以看作是官方的自定义hook,上面的方法等价于下面的方法
const App = observer(() => {
const state = useLocalObservable(() => new Mystore())
return <>
<Condition condition={myState.condtion} onChange={state.onConditionChange} />
<Table data={myState.tableList} onPaigionChange={state.onConditionChange} />
</>
})
ReactDOM.render(<App />, document.body)
从上面的示例中可以看到,组件都会使用observer函数包裹了,这是当state发生变化时,mobx确保组件重新渲染了。它的原理是一个高阶组件,后续会详细说说这个高阶组件的原理。
有的时候你需要使用render api的方式渲染组件,而且需要渲染的子组件是可观察的,那么可以使用Observer组件.
const Address = observer(({address}) => <div>{address}</>)
const App = () => {
const state = useLocalObservable(() => new Mystore())
return <Observer>
{
() => state.getInBeijing.map(address => <Address address={address} />)
}
</Observer>
}
注意,如果上面的Address组件如果需要是可观察的,需要使用observer函数或者Observer组件包裹
const Address = ({address}) => <div>{address}</>
const App = () => {
const state = useLocalObservable(() => new Mystore())
return <>
{
() => state.getInBeijing.map(address => <Observer>
<Address address={address} />
</Observer>)
}
</>
}
在mobx6开始已经不建议使用注解的写法了,但是你仍然可以使用这个功能。
使用时,需要先给idea设置注解识别功能,然后配置相关的babel插件,这里不展开了,详细的内容可以看看这里
今天的学习内容就这些了,下篇文章会先将整理好的面经发布出来,然后继续分享在新公司的一些学习笔记。希望可以帮助更多的人。文章如果有错误的地方欢迎指正!
因为新公司离家更近了,每天节省了两个小时的通勤时间,我会都用于更新学习笔记,所以一定要记得关注我的公众号:萌萌哒草头将军
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。