闽公网安备 35020302035485号
3.虽然 Mobx 很快,还是请遵守 Mobx 的性能守则
.应用级别状态:应用是处于离线还是上线状态,用户是否登录
.store 经过 selector 计算之后注入的
那么当我们尝试追溯或者 debug 某个属性的状态来源时,面临的是 (3 × 3 = )9 种的可能,尤其是当你在把不同的状态拆分为不同的 reducer 时,这会带来非常大的困恼。所以我个人的第一条件建议是:尽可能的将状态都存储在同一处 Mobx 中。
注意这里有几个关键词:
尽可能的:用万能的二分法进行划分,我们总是能把状态划分为“共享的”(比如上面说的“应用级别状态”)和“非共享的”(比如对应于某个特定业务)。鉴于共享状态需要被全应用所引用,所以无法把它分配到某个特定业务的状态下,而需要独立出来。
同一处:在设计状态的时候应该遵循两条基本的原则:
1) 每个页面应该有自己的状态;
2) 每个被复用的组件应该有自己的状态;根据以上两点可以推断,React 组件应该是 stateless 的
const Joi = require('joi');
// 堆代码 duidaima.com
const schema = Joi.object().keys({
username: Joi.string().alphanum().min(3).max(30).required(),
password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
access_token: [Joi.string(), Joi.number()],
birthyear: Joi.number().integer().min(1900).max(2013),
email: Joi.string().email({ minDomainAtoms: 2 })
})
使类似的 schema 类库非常多,最简单的使用 ImmutableJS 里的 Record 类型也能起到约束的作用,这里就不展开了。Do you want to keep this data consistent while hot-reloading UI components (which may lose their internal state when swapped)?
@withMobx(props => {
return {
userStore: new UserStore()
}
})
@observer
export default class UserForm extends Component {
}
withMobx 的实现也非常简单,鉴于我们这里并不是高阶组件节目,这里就不鉴赏高阶组件的各种开发模式,你也可以借助 acdlite/recompose 创建。这里直接亮出手写答案:export default function withMobx(injectFunction) {
return function(ComposedComponent) {
return class extends React.Component {
constructor(props) {
super(props);
this.injectedProps = injectFunction(props);
}
render() {
// const injectedProps = injectFunction(this.props);
return <ComposedComponent {...this.props} {...this.injectedProps} />;
}
};
};
}
值得玩味的事情是 this.injectedProps 的计算位置,是放在即将返回的匿名类的构造函数中。但事实上它可以存在于其他的位置,比如上述代码的注释中,即 render 函数里。但是这样可能会导致一些问题的发生,这里可以发挥你们的想象力。本质上这和组件自己的 state 类似,只不过我们把 state 交给 Mobx 实现,然后通过高阶组件把它们粘合在一起。class Person extends React.Component {
constructor(props) {
super(props)
}
render() {
console.log('Person Render')
const {name} = this.props
return <li>{name}</li>
}
}
@inject("store")
@observer
class App extends React.Component {
constructor(props) {
super(props);
setInterval(this.props.store.updateSomeonesName, 1000 * 1)
}
render() {
console.log('App Render')
const list = this.props.store.list
return <ul>
{list.map((person) => {
return <Person key={person.name} name={person.name} ></Person>
})}
</ul>
}
}
updateSomeonesName方法会随机的更改列表中某个对象的name字段。从实际运行的状态看,即使只有一个对象的字段发生了更改,整个<App />和其他未修改的对象的<Person />组件都会重新进行渲染。改善这个问题的方法之一,就是给Person组件同样以mobx-react类库的observer进行“装饰”:@observer
class Person extends React.Component {
observer的作用用原文的话说就是:Function (and decorator) that converts a React component definition, React component class or stand-alone render function into a reactive component, which tracks which observables are used by render and automatically re-renders the component when one of these values changes.@observer
class Person extends React.Component {
constructor(props) {
super(props)
}
render() {
// 1:
return <PersonName person={this.props.person}></PersonName>
// 2:
return <PersonName name={this.props.person.name}></PersonName>
}
}
如果你使用了 1 的写法,那么当person.name发生更改时,<Person />组件不会重新渲染,只有 <PersonName /> 会重新渲染