微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

react+redux+webpack移动端项目总结

前言

距离我进新公司也有一个多月,这一个月的事件使用react写了一个项目,期间断断续续重构了两三次,目前已经完成第一阶段测试,也总结分享一些使用react的一些坑。

react

先啰嗦几句讲一下react原理,新人可以认真看下,老鸟可跳过。

react并没有像其他如vue,ng一样采用MVVM模式,所谓MVVM模式,狭义来说就是将模板与数据绑定在一起,当数据发生改变时,模板自动更新,这是中间的VM,最左边的M可以理解为我们看到的页面,而最右边的M可以理解为原始数据(例如数据库数据)。
其实要知道,这些框架模式归根结底的目的希望使代码更容易开发和维护。当你写一个页面你不觉得什么,但是当你的页面越来越庞大,越来越复杂,开发人员走了一批又一批的时候,你就会明白了。而如何解决,现在比较公认的理念一个是组件化,将页面拆分成一个个组件,其实拆分成组件的目的并不全是为了复用,我觉得更多是为了维护;一个就是希望让应用层的编程能更专注于业务逻辑,那么这些框架都去做了处理,减少了大量DOM操作,让业务开发更加专注。

那么我们看看react采用的是什么原理。其实react采用的方法简单粗暴:它并没有对模板做数据绑定,而是每当数据变化时,就重新渲染模板。这有一个很大的好处就是每当数据变化时,对页面来说只有一次IO操作,而单纯的双向绑定更新DOM会有很多次;但有一个问题,如果只改变了一个dom的数据,整个模板都会重新渲染。那react解决方法是每当数据改变时,就进行对比。

那么该如何对比呢,最简单的方法是每当数据改变,就去页面获取相应的DOM信息,然后与现在的DOM信息做比较。这个方法有个致命的缺点就是每次有DOM改变,就会有许多读取操作,IO操作太多,很影响性能。那么可以通过空间换时间的方法,将DOM信息保存起来,就避免了去页面获取信息的IO操作。那么我们看看一个真实DOM有多少数据

虚拟DOM

如果我们把所有原生DOM缓存起来进行比较显然内存会爆炸,而我们所需要的仅仅是几个为数不多的状态信息(例如style啊这些),这时虚拟DOM应运而生,如果说原生DOM是一块猪肉,那么虚拟DOM就是这块猪肉中多精肉,他剔除了那些对我们来说没有太多意义相反还占内存的状态信息,而只将我们所需要的内容留了下来。那虚拟DOM该如何比较呢,就涉及到了虚拟DOM的diff算法。

diff算法

简单来说两个模板就像两棵树一样,传统的树对比的时间复杂度是O^3,也就是说要整棵树遍历三次,那react根据DOM的特点:跨层级的操作较少。什么叫跨层级,举个例子一个组件有三个层级关系(嵌套三层),把第二层的div放到第三层就属于跨层级操作。这种操作其实还是比较少的,react官方也不推荐这么写。那么利用这个特点,react只diff同层级的DOM。这里涉及以下几种情况

  1. tag变化(标签变化)

  2. 属性变化

第二种没什么好说,就是进行同层级对比。这里详细说一下第一种变化,react的方法是当前层级往下全部删除替换,简单暴力。在业务开发来看,你同层级类型都不同了,比如div变成了input,那么你的子组件相同的几率也较小,因此不如整个替换简单暴力。同时这也说明为什么列表需要key属性,因为列表很多的删除操作对于react来说是不知道的,它需要一个key来了解到底谁是谁。

踩过的一些坑

state

作为前端,拿到原型第一件事就是要与你的产品充分沟通,评估该项目是否需要引入redux,那么如何确定需要引入redux呢,这边有几点:

  1. 页面之间组件之间通信较多,且是跨层级的;

  2. 页面的交互逻辑较复杂,且经常引起多处组件变化。

再然后就是对state的设计。对于后台的返回的数据,你并不知道到底哪些是有用的,哪些可能现在没用以后有用,因此我的建议是对于每个api都将它存在一个object里。那么组件该如何去获取,首先不能全部通过顶部container获取依次往下传,也不能粒度很细的去一个个connect,我的建议是对于一个object,可以用一个container去connect,粒度把握主要看你的业务需求。

还有一个要不要全局都使用redux。我的观点是否定的,我认为对于局部一个组件内的状态完全可以通过setState来满足。

图片处理

首先将图片做一些划分。例如以500k作为分界,小于500k为小图片,否则是大图片。对于小图片,我们需要做如下判断:

  1. 页面是否重复使用?是就用雪碧图,否则转base64.

  2. 对于大图片,可以进行压缩后使用。

base64可以用webpack的url-loader替换。
举个例子

require('url?limit=250!./xxx.png')
//这里就会使用url-loader,假如图片小于250,就会转为base64

移动端适配

对于适配,我所知比较好的方法是利用rem作为单位,将页面宽度等分成10个rem,根据页面动态的用js去改变font-size,达到适配不同浏览器的目的。例如爱疯宽320px,那么font-size设置为32px。那么10rem就是等于整个屏幕的宽度。但是有一个特例就是高清屏,一般高清屏的物理像素是实际像素的2倍,那么当你想显示一个宽度为1的边框时,在普通屏幕是1px,在高清屏可以有0.5px(问题是很多浏览器不支持,为将0.5px认为是0)。虽然都使用1px在两者屏幕上实际上是一样的,但是高清屏里的1px在射鸡师眼里是无法达到他对于1的要求的。于是就有一些解决方案,比较简单是是使用transform:scale(0.5)。那么还有一种解决方案就是阿里的移动端解决方案,原理是将页面整体scale缩小,然后放大font-size,来保证rem为单位的布局不变,但是px为单位的会被缩小。

性能提升

首先先确定需求,确实有这个需求的时候再谈。

懒加载

webpack其实会帮我们做第三方依赖的懒加载处理,那么针对react,我们可以通过现成的库来实现懒加载react-lazyload,或者使用webpack现成的

require.ensure([],()=>{
require('public.js')
})

来实现。

shouldComponentUpdate

其实这个钩子可以极大的帮助我们去提升性能,由于它的存在,我们可以自己判断哪些是我们组件需要的state,哪些是不需要的,那么这就可以阻止react进行不必要diff。但是有一个问题就是对于对象我们很难去判断他们是否相等,那么可以通过immutableJs的fromJS和is方法解决这个问题。其实immutableJs的好处远不止于此,目前我也尚在填坑中。

使用不可变数据,可以更好的达到函数式编程,不仅利于单元测试,也更有利于后期维护整个大的state。因为他的不可变特点,我们不会在不经意见不小心改变了state,而引起不必要的问题。

创建组件的痛点

为了使组件中的css作用域相互独立,一般采用Css Module,那么为了使组件看上去更像组件,并且易于后期维护,一般我们会这样结构化组件文件

那么对于每一个初始的jsx,我们大多会这样初始化

import s from './App.scss'
import{Component} from 'react';//得到组件方法

class App extends Component{
  
  render(){
    return (
      <div className={s.container}>
      </div>
    )
  } 
}
export default App;

不难发现,对于每一个组件,我都需要去手动的创建这些文件文件夹,而这些操作其实是重复且无意义的劳动,于是我造了一个小轮子,一个命令行小工具,来解决这个痛点。
react-component-maker,欢迎猛戳点star!

结语

困了,本宝宝要睡觉了,还有的内容下次再说吧,再见。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...