《当讨论心智负担时,我们到底应该讨论什么?》

813 阅读3分钟

首先要明确的是,react 以及背后的函数式编程理念确实属于一种较为复杂与非“常规”的编程理念。但是这就表示一旦开发中遇到和预期不一样的情况,就要归类于心智负担吗? 理解难度大和理解错误是完全不同的两件事。心智负担应当是理念理解难度大,所导致正确解法实现困难,写出错误的代码。这是能力的问题。

但是,基于错误的理解编写代码,获得自以为预期以外的错误,很难说是某些语言或框架的心智负担。这应当属于开发者的责任。这是态度的问题。(当然理解的困难也加剧了这种情况的发生)

react,或者说函数式编程的核心,就在于控制副作用。让副作用尽量薄,写出尽可能多的纯函数。

具体到 react 上,实际上就是 view = f state 一个公式而已。渲染组件本身是纯函数,保证固定的 state 可以映射到固定的 view 上。(所以这也是为什么组件应该要么只有状态,要么只有渲染的原因)然后 IO 触发状态的刷新,刷完以后又是一轮 view = f state 的映射。

的吧的说这么一大堆的目的是什么呢?核心的观点是:对于习惯命令式编程(暂且这么称呼)的程序员来说,不能把 react 仅仅当作一个前端 view 层的框架来看待,它同时还是完全不同编程理念的体现。因而,如果觉得函数式的思维复杂难懂,写了代码写不漂亮、写不正确,可以理解,这是函数式理念本身的问题;但是还保留原来命令式的思维,想完全复用已有经验,一旦不合预期就大呼 react 心智负担,那是这个程序员自身态度有毛病。

回到文章。首先,react 的理念 view = f state,本身 state hook 就是用来承载 state 的。把 jsx 放到 state 数组里面,实际上就是放弃了每次 render 时框架的 diff,手动维护一个 vdom 的更新。(其实一般就是没有更新)把当时的 state 封存在了这个 jsx 里面,那之后这个组件触发的 IO 自然是基于这个旧有的状态更新。

其次,这种过时 state 触发 IO 的场景也并不是没有,并且早就有解决方案。实际上这种场景就是经典的异步请求。在异步请求结束时,请求发起时的状态大概率是过时的。解决很简单,大家也都知道,只需要在 setState 里面传入函数就可以了。方法很易懂,但是背后的理念:尽可能写纯函数,隔离副作用,又有多少人真正知道呢?

要明确一点,如果打算使用函数式的理念了。那就一定要对副作用有足够的敏感度。所谓副作用,在变量本身不可变的前提下,实际就是 IO。因为 IO 永远是运行时才可以被确定的,但是又无法避免。所以对这种 click 事件,一定要能察觉出来其中包含的副作用,并将妥善隔离。

总而言之,只要遇到困难就抱怨某某框架某某语言不是合适的对待新理念的态度。明晰问题类型,那些确实是 bad part 的部分实在没有必要捏着鼻子去了解;但是不妨也试着思考思考是否存在自己理解上的不足。保持开放的学习心态才是提升技术,也是提升自己技术热情的合理方式。

以上