上篇博文至今,又间隔了一个多月。其实这一个月自我感觉成长了不少,学到也用到了不少东西。一直懒于动笔拖到了七月的尾巴。
工作上
工作上正式开搞了一个新项目。前端这边React全家桶。React全家桶无非就那点东西,但这回确实收获了不少。最大的收获还是工程化和拆分这一块。之前自己写前端项目亦或是在无二写RN回头来看离工程化差的好远,这次的工作才真真切切感受到了什么是前端工程。
在这次工作中,在等待后端提供接口的时间,首先做了一个纯JS的组件库,组件库分通用组件和逻辑组件两种。一开始自己不太理解已经有Antd这样UI组件库,为什么还要自己搞一套。和老大请教之后给出的解释是这样的我们所做的后台之后还会面向C端,与其用一个大而全的开源项目修改,不如一点点完善一个小项目,可以避免很多冗余的代码同时项目不仅仅只是纯UI组件还会有很多业务强相关的组件,先完善搞好组件之后正式开发项目在页面上甩组件就是咯。
在组件库开发过程中,为了方便开发,使用了Storybook这个神器。Storybook可以说是一个UI组件的开发环境,很方便的去交互测试组件,以及生成组件文档。其实官方文档也相当清楚。正如它页面展示的动图一样,交互体验去开发组件,调试测试都很方面。这里暂时不展开说了了,后续专门写一篇介绍一下。样式组件之外就是和业务强关联的业务组件。自己在这一块的开发做的不是很好,没有想清业务便着手开发在之后项目使用中,发现这里有不足那里有不足返工添加属性逻辑反反复复好几次。以后还是要先想好理清楚之后再coding。
组件库做得差不多了、后端API也开发完毕了终于到了项目开发,总体来说有了组件库的开发铺垫,正式开发起来非常效率。
在豆瓣工作最直观的感受就是工作上的任务、文档清晰明了,所有研发都心照不宣地维护这个传统和文化,这点真的很难得。提issue讨论确定需求,projects任务排期。开发之后提PR,同事仔细地Review代码,最后同事的一句LGTM
结束这个PR的开发。这一系列看似理所因当的,规范的流程操作,在国内快文化下太难得了。
回到前端工程上来,首先是项目拆分的很细致。就说Redux这一块actions、const、effect、reducer、sagas、store(这里是之后一个文件configure-store.js进行redux的一些配置包括区分开发和生产环境以及saga的配置)足足有六个文件夹。一开始上手的时候很懵逼,不过确实很清晰。自己在工作之余的学习中,自己的那个项目也完全按工作中的细化规模自己实践了一番。Redux虽说繁琐,不过真正搞清楚Redux工作流,熟练上手之后。Redux这种清晰的数据变化流程不要太赞。我认为Redux最能提升的不是开发效率,而是维护效率。这就是Redux的可预测性
吧。再有就是从同事的代码上学到了好多,在之前的公司完全没有这种感受,自己还是要加油
工作之外
这一个月,为了搞定工作以及尝试一些新东西搞了这么一个React项目Irelia,除了上面说的细化redux开发流程之外,主要尝试了完全使用/Immutable.js去管理数据以及Styled-components这种组件的方式完成样式的书写,实践证明这两个库真的是超级好用。
先说Immutable.js,它弥补了Javascript没有不可变数据结构的问题。由于是不可变的,可以放心的对对象进行任意操作。在全局使用之后,我们就不用担心引用类型的变量所引发的一系列副作用咯。
话说工作上的项目没用immutable.js,上周五就遇到了这样一个问题。如果用Immutable.js就可以完全杜绝这块的问题了,非常省心。当然深拷贝也可以做到(差别在于性能)。immutable.js提供了很多强大的API,配合React以及Redux可以说高效、方便、安全。
reducer中使用
view调用
需要注意的点:
- 既然全局使用了immutable.js,再生成新数据,获取新数据传递到action之前一定要注意将其转化成immutable(大部分情况使用fromJS就好:fromJS会包裹一个JS对象使其变成immutable对象。(内部的对象也会变))总结一句话就是:同一类型,才不会出错;
- pureComponent和immutable.js完美契合可以放心大胆的用。
再来说说Styled-components,可以说是css in js上的又一种尝试。让样式也组件化同时逻辑组件和展示组件分离。使用styled-components不需要再使用className属性来控制样式,而是将样式写成更具语义化的组件的形式。Styled-components的写法可以让样式暴露props让外层JS去控制。这样我们就不需要ClassName、style这样的中间人
。
此外Styled-components支持全部Css特性,归根结底本质还是css,什么动画、伪类都不在话下。还有一个优点就是,我们不再需要考虑className命名问题。使用Styled-components会给生成的React组件添加一个值为随机字符串的className。使用同一个Styled-components生成的多个React组件的className是不同的,这种随机className的机制使得组件之间的className值不会冲突,从而解决了CSS全局作用域的问题,也省去了命名的麻烦。
这种控制样式的编程方式不光能解决CSS全局作用域的问题,而且移除了样式和组件间的映射关系真的好用。
Note
新版React不再推荐对象的方式去改变
1
2
3this.setState({
a: 1
})推荐异步函数的形式代替对象传入setState中
1
2
3
4
5this.setState((prevState) => {
return {
a: prevState.a + 1
}
})其中
preState
等价于this.state想在最外层包一层,但又不想被显示。可以试试React16引入的Fragment。一个JSX空标签
ref={(input) => { this.input = input }}这种使用ref获取dom,一定要记得setState是异步的
说到React ref,React16.3加入了新的React.createRef API。目前获取ref dom元素有三种方法 1)String Ref 2)Callback Ref 3)React.createRef
React官方表示String Ref将会在未来版本被移出,建议用户使用Callback Ref、React.createRef来代替
String Ref一些问题:- React元素在创建和更新的过程中,定义成String类型的ref会被封装为一个闭包函数,等待commit阶段被执行,这样会对React性能产生一些影响。
- String Ref无法被组合,当父组件已经给子组件传递了ref,那么我们就无法再在子组件上添加ref了, Callback Ref方式便可避免。
- 在根组件上使用无法生效。
另外,React16还另外提供了一个关于ref的API
React.forwardRef
,主要用于穿过父元素直接获取子元素的ref。生命周期中componentWillReceiveProps。没有props参数是不会执行的,只有父组件接受了props才会执行,只要父组件render函数重新执行了,子组件componentWillReceiveProps就会执行。
可以通过React16生命周期中componentDidCatch,创建一个error-boundary,用来捕获其内嵌套的组件生命周期发生的错误。(* 无法捕获异步以及事件回调引发的错误)
便捷的深拷贝
JSON.parse(JSON.stringify(obj))
判断两个对象是否相等,如果项目中没有使用immutable.js,可以引入lodash.isequal
1
2import isEqual from 'lodash.isequal'
isEqual(obj1, obj2)Redux
reducer可以接受state,但绝对不能修改state;store必须是唯一的;只有store才能改变自己的内容;reducer必须纯函数不能有副作用;state在其他地方只读只有在store中才能修改。每一块功能拆分一个小store,通过combineReducers合并。每一个功能(组件)的store可以使用这样的模板:
其中index.js可以这么写1
2
3
4
5import reducer from './reducer'
import * as actionCreators from './actionCreators'
import * as constants from './constants'
export { reducer, actionCreators, constants }use redux chrome tool
1
2
3
4
5
6
7
8
9
10
11import { createStore, compose, applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import reducer from './reducer'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(reducer, composeEnhancers(
applyMiddleware(thunk)
))
export default storethis.props.children可以读取组件下的子节点。this.props.children可以用React.Children.map遍历子节点,好处是不用担心数据类型是undefined还是Obj
在项目中最好分离开业务组件和UI组件。UI组件能写成Stateless方式还是要写成这种方式以提高性能。
Styled-components中可以通过innerRef拿到真实Dom
实现react页面之间的异步加载操作可以尝试使用
react-loadable
这个组件
以上~~~~