React.js Essentials
目录
安装开发环境
- Twitter Streaming API:略
- Filtering data with Snapkite Engine
- npm install --global node-gyp
- npm install --save-dev browserify(可在客户端重用Node库?)
- Gulp.js
- gulpfile.js:(内容略)有点意思
- npm install --save-dev babelify(允许JSX语法)
创建你的第一个React Element
- 理解虚拟DOM
- 用户输入事件 vs 服务器事件(?)
- 只要state有变化,就会rerender
- <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.0-beta3/react.js"></script>
- npm install --save react@0.14.0-beta3 react-dom@0.14.0-beta3
- ReactNode
- ReactElement
- React.createElement(type, props, children);
- data-reactid=".0" ?
- ReactText
- ReactElement
- ReactFragment
- React.createFactory('li') //这里开始有点FP的感觉了,=> 内建工厂函数: React.DOM.li()
- ReactDOM.render(ReactElement, DOMElement, callback);
- 服务器端渲染(客户端只看到格式化后的html):ReactDOMServer.renderToString(ReactElement);
- JSX
- 注意:JSX相当于把UI模板嵌在代码里,而以前的JSP是在代码嵌在模板里!
React组件(状态机)
- Stateless vs stateful
- React.createClass({render: ... });
- render不管理状态
- 传递数据:this.props this.data
- React components are composable(可组合的)
- 分离组件为2个方面:处理UI交互、render data
- 少部分组件是有状态的,放在组合树的顶层,并传递props给下面的无状态的组件
- getInitialState: ...
- setState(dataFunc, callback)
- 指定UI交互逻辑:onClick: ...
- Keep the minimal possible representation of a component's state in a state object
- SyntheticEvent
- 支持触摸:React.initializeTouchEvents(true)
使React组件变成响应式的
- 尽可能清楚地定义‘问题’
- 计划你的React组件层次树(顶层是Application)
- var Application = require('./components/Application.react'); //嗯?
- Application.react.js:嵌套包含子组件(父依赖于子,但子不依赖于父?)
- <Stream onAddTweetToCollection={this.addTweetToCollection} /> //What-the-fuck?!组件以tag元素的形式嵌入在JSX中
- 现代化的Web前端开发:模块化、可组合
- 使用Bootstrap布局?
//某种表格风格的布局?
- 子组件怎样更新父的state:父在子上注册/传递一个callback。。。(delegate to parent)
- 简单一句话:不能直接更新(必须通过callback的方法),这里感觉‘父组件’就像一个独立进程/线程的EventLoop...
- 同样,父组件也不能越过子直接向底层后台组件传递数据(优化:Flux)
React组件里使用其他库
- componentDidMount、componentWillUnmount:用于导入第3方依赖的hook回调点?
- 组件的lifecycle方法:3个阶段
- Mounting:插入DOM
- getInitialState()
- componentWillMount()
- render()
- componentDidMount()
- Updating:更新虚拟DOM
- 留到下一节讲解
- Unmounting:从DOM移出
- componentWillUnmount
- Mounting:插入DOM
更新React组件
- updating阶段:
- componentWillReceiveProps():比较this.props与nextProps,调用setState
- shouldComponentUpdate():返回false,则跳过此组件的更新
- componentWillUpdate():nextProps、nextState
- render()
- componentDidUpdate():prevProps、prevState(返回之前的model状态?)
- style属性:传递CSS规则in a JS对象
- 缺点:CSP
- propTypes:用于验证属性全部收到(?)
- propertyName: function (properties, propertyName, componentName) { ... return new Error("..."); ... }
- 插一句话:感觉JSX不就是C#里的XAML嘛,只不过XAML是服务器端的
创建复杂的React组件
- 略
Jest测试
- Jest能够mock用require()导入的module,怎么做到的?
- jest.dontMock('../TweetUtils');
- jest.autoMockOff(); //替换了require函数的默认实现?
- jest样例:
- expect(actualIsEmptyCollectionValue).toBeDefined();
- expect(actualIsEmptyCollectionValue).not.toBe(true); //见鬼,这个not是什么语法??
- ReactDOM.findDOMNode() ?
- 测试jsx:npm install --save-dev babel-jest
Flux
- Application > Stream > StreamTweet > Tweet
- Flux makes sure that all our data flows only in a single direction.
- 4个逻辑实体:
- Actions(所有的数据修改请求都必须包装成一个‘动作’)
- Dispatcher(有点像是PubSub模型)
- Stores
- Views
- Actions > Dispatcher > Stores
- var AppDispatcher = require('../dispatcher/AppDispatcher');
- var EventEmitter = require('events').EventEmitter;
- var assign = require('object-assign');(Nodejs的模块实在是太泛滥了)
Flux无痛项目维护
- Decoupling concerns with Flux
- Code-wise, this might look like a small change, but it's a significant architectural improvement
- ... tweet: TweetStore.getTweet() //不再是通过props传递,而是通过全局的store对象的getter方法
- Flux的没有setter意味着不能做局部的mutate,必须通过Action(这相当于一个全局的diff,UNDO/REDO)
- componentDidMount: function () {
- TweetStore.addChangeListener(this.onTweetChange); //注册callback,得到周期性的更新通知
- 注意,需要在componentWillUnmount里移除listener
- Scale:one-way data flow
- Application不再需要管理state,交给各个store(这里是Stream和Collection)
- 重构CollectionControls:...
- 思考:在Android应用开发里是否也需要应用Flux的设计原则呢?普通MVC只要求先更新Model,然后触发UI更新;而Flux则要求Model的更新都必须封装为一个Action对象