您的位置:首页 > Web前端

前端演进思考

2019-12-03 20:33 337 查看

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

0. 从模型说起

原生JS/jQuery 这时候开发者需要手动处理 BindChangeUpdate,jQuery 相比原生 JS,简化了操作,屏蔽了浏览器的兼容性。

三大框架 这时候开发者只需处理 BindChange,框架自动完成 Update。框架使用一套高效的 diff 算法最小化更新 DOM,因此除了简化开发者工作,还带来了前端性能的提升。

1. 组件思想

除此之外,框架另一个突出贡献是引入了 组件 思想,这使我们能将一个复杂的应用拆成多个组件逐个击破,还使我们能用一套基础组件组合出各种各样的应用,以高效的响应业务需求。

但是在大型应用中,这种方式又出现 2个严重的问题

跨组件数据传递** 在单向数据流中,Props down & Event up,跨组件的数据传递非常困难,如上图的,中间2个组件即使不关注数据,也必须写上相关代码让数据传下来。联想到现实中,我们说的组织层级过多导致流程冗杂,也是类似的道理。

意外数据修改 JS 的数据类型和 Java 类似,除了少数几个基础类型是值,其他的都是 引用,因此在某个子组件里的数据修改,很容易影响到其他地方。尽管框架一再警告 props 应该看作只读的,但受制于语言特性,框架无法阻止意外的修改。

从开发者角度,我们也希望能 在一个地方就看到整个应用的状态,而不是深入到各个组件里去查看。

2. 状态管理

对于跨组件数据共享问题,一个自然的想法是:为啥不写一个公共的模块,把共享的变量都放到里面呢,之前写后端也是这样的呀?

前端还真不能这么干!根本原因在于我们要依赖框架的自动 Update 能力(第一张图),React 中 有且仅有两种情况会触发界面更新

  • state 变化(setState
  • context 变化(Redux)

(说 forceUpdate 的,看我眼神……)

于是 Redux 登场,理想情况下,数据流会被规整成下图那样:

但是 Redux 也不是免费的,它带来两个我一直耿耿于怀的问题:

组件不能任意组合 组件连接 Redux 以后,即丧失了封闭性,如果页面上出现这样一个组件的两个实例,那这两个实例的状态就会互相影响。

割裂的逻辑 强行将逻辑拆成 actionreducer,一个功能要改3处代码,怎么看怎么蠢。

3. Maybe hooks?

较早前就听过 hooks,当时并不以为意,想着无非是给函数组件注入状态而已。数据和方法绑定,扒着指头数也就3种方式:

  • 模块
  • 闭包

类就挺直观的呀,干吗要要用闭包这种 tricky 方式去做?直到最近读文档,才发现这可能就是我一直心心念的 既要有清晰的数据流,又不割裂逻辑 的实现方式,抄 一段代码 感受感受:

class FriendStatusWithCounter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0, isOnline: null };
this.handleStatusChange = this.handleStatusChange.bind(this);
}

componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
ChatAPI.subscribeToFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}

componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
}

componentWillUnmount() {
ChatAPI.unsubscribeFromFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}

handleStatusChange(status) {
this.setState({
isOnline: status.isOnline
});
}
// ...
function FriendStatusWithCounter(props) {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});

const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}

ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
// ...
}

看,hooks 能不受 class 组件生命周期钩子的限制,将逻辑相关的代码集中到一起了!

4. 其他

state 里该放什么数据 由于我们使用 state 的本质是利用框架的自动更新 DOM 的能力,因此 state 里只需放 界面相关 的数据。

Redux 里该放什么数据 Redux 的职责更多是数据管理,开发实践中,随业务迭代接口数据变动会比较频繁,适宜放 Redux 中;另外跨组件共享的数据也要放 Redux 中。总结起来就是 界面相关 && (服务端的 || 共享的) 应该放 Redux 中。

那岂不是和数据全貌相差太大了 只把界面相关的数据放 state 和 redux 里,会不会与业务数据全貌相差太大了呢?我认为不会,在后端“读写分离”的实践中,一般做法只是将查询和写入的服务放到不同的实例上,而更进一步的做法是 查询用的表和写入用的表都是不一样的!state 和 Redux 就是类似这样的读模型;界面无关的数据,完全可以再放到一个公共模块里。

作者:杨少军

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  React redux jQuery BIND ReactJS
相关文章推荐