react首先是类似一个组件库的js文件,包含view和controller的库。
react组件根据平台本身可以映射成原生控件和web dom。
采用babel的编译工具将jsx转换成js来描述对应的元素。
无状态组件:使用无状态函数构建的组件成为无状态组件,只传入props,context两个参数,不存在state,没有生命周期方法。无状态组件在调用时不会创建新实例,避免了不必要的检查和内存分配。
react-dom:findDOMNode(ReactComponent) 获取真正的DOM元素,返回该react组件对应的DOM节点。
react-dom:unstable_renderSubtreeIntoContainer: ReactMount._renderSubtreeIntoContainer(parentComponent,
nextElement, container, callback)。将目标元素插入指定节点container
render: ReactMount._renderSubtreeIntoContainer(null, nextElement, container, callback)。 两者的区别在于是否传入父节点。
React.cloneElement: 给指定组件传递props
React.children: 获取当前组件的子组件
合成事件:
事件委派:React并不会把事件处理函数直接绑定到 真实的节点上,而是把所有事件绑定到结构的最外层,使用一个统一的事件监听器,这个事件监 听器上维持了一个映射来保存所有组件内部的事件监听和处理函数。当组件挂载或卸载时,只是 在这个统一的事件监听器上插入或删除一些对象;当事件发生时,首先被这个统一的事件监听器 处理,然后在映射里找到真正的事件处理函数并调用。
自动绑定:React 组件中,每个方法的上下文都会指向该组件的实例,即自动绑定 this 为当前组件。或者利用箭头函数自动获取当前this。
事件捕获:会优先调用结构树最外层的元素上绑定的事件监听器,然后依 次向内调用,一直调用到目标元素上的事件监听器为止。
事件冒泡:则与事件捕获的表现相反,它会从目标元素向外传播事件,由内而外直到最外层。
React的合成事件则并没有实现事件捕获,仅仅支持了事件冒泡机制。
非受控组件:一个表单组件没有 value props(单选按钮和复选框对应的是 checked prop) 时,就可以称为非受控组件。
它是一种反模式,它的值不受组件自身的 state 或 props 控制。通常, 需要通过为其添加 ref prop 来访问渲染后的底层 DOM 元素。
classnames样式库:classNames({ 'btn': true, 'btn-pressed': this.state.isPressed, 'btn-over': !this.state.isPressed && this.state.isHovered,});
CSS Modules: 能最大化地结合现有 CSS 生态和 JavaScript 模块化能力,其 API 非常简洁。 发布时依旧编译出单独的 JavaScript 和 CSS 文件。
现在,webpack css-loader 内置 CSS Modules 功能。
启用 CSS Modules 的代码如下:
// webpack.config.js
css?modules&localIdentName=[name]__[local]-[hash:base64:5]
加上 modules 即为启用,其中 localIdentName 是设置生成样式的命名规则。
使用了 CSS Modules 后,就相当于给每个 class 名外加了 :local,以此来实现样式的局部化。如果我们想切换到全局模式,可以使用 :global 包裹
对于样式复用,CSS Modules 只提供了唯一的方式来处理——composes 组合。
/* components/Button.css */ .base { /* 所有通用的样式 */ }
/* settings.css */.primary-color { color: #f40; }
.primary {composes: base; composes: $primary-color from './settings.css'; /* primary 其他样式 */}
如果不想频繁地输入 styles.**,可以使用 react-css-modules 库。它通过高阶组件的形式来 避免重复输入 styles.**。可以这么写---styleName="root"
使用 CSS Modules,容易使用 :global 去解决特殊情况,使用 react-css-modules 可写成 <div className="global-css" styleName="local-module"></div>,
这种形式轻松对应全局和局部;
跨级组件通信:
在子组件定义 static contextTypes = {color: PropTypes.string} ,通过this.context.color获取顶层组件的color属性
在顶层组件定义 static childContextTypes = {color: PropTypes.string}, 实现方法 getChildContext() {return{color: 'red'}
没有嵌套关系的,那只能通过可以影响全局的一些机制去考虑。import { EventEmitter } from 'events';
在 componentDidMount 事件中,如果组件挂载完成,再订阅事件;当组件卸载的时候,在 componentWillUnmount 事件中取消事件的订阅。
对于广义的 mixin 方法,就是用赋值的方式将 mixin 对象里的方法都挂载到原对象上,来实 现对对象的混入。
React 在使用 createClass 构建组件时提供了 mixin 属性,mixins: ['xxx','xxx'],
在不同的 mixin 里实现两个名字一样的普通方法,这会造成冲突。因此, 在 React 中是不允许出现重名普通方法的 mixin。
如果是 React 生命周期定义的方法,则会将各个模块的生命周期方法叠加在一起顺序执行。
使用我们推荐的 ES6 classes 形式构建组件时,它并不支持 mixin。
对于实现 mixin 方法来说,这就没什么不一样了。但既然讲到了语法糖,就来讲讲另一个语 法糖 decorator,正巧可以用来实现 class 上的 mixin。
core-decorators 库为开发者提供了一些实用的 decorator,其中实现了我们正想要的 @mixin。 下面解读一下其核心实现:
function handleClass(target, mixins) {
if (!mixins.length) { throw new SyntaxError(`@mixin() class ${target.name} requires at least one mixin as an argument`); }
for (let i = 0, l = mixins.length; i < l; i++) {
// 获取 mixins 的 attributes 对象
const descs = getOwnPropertyDescriptors(mixins[i]);
// 批量定义 mixins 的 attributes 对象
for (const key in descs) {
if (!(key in target.prototype)){
defineProperty(target.prototype, key, descs[key]);
}
}
}
}
源代码十分简单,它将每一个 mixin 对象的方法都叠加到 target 对象的原型上 以达到 mixin 的目的。这样,就可以用 @mixin 来做多个重用模块的叠加了。
这里用了getOwnPropertyDescriptor 和 defineProperty 这两个方法,
好处在于 defineProperty 这个方法,也就是定义与赋值的区别,定义是 对已有的定义,赋值则是覆盖已有的定义。所以说前者并不会覆盖已有方法,但后者会。
高阶组件:
属性代理是常见高阶组件的实现方法
const MyContainer = (WrappedComponent) =>
class extends Component {---这里将Component替换成WrappedComponent就实现了反向继承,除了一些静态方法,包括生命周期,state,各种function,我们都可以得到。
我们同时可以以此进行hijack(劫持),也就是控制它的render函数。在render()中调用superRender(),然后通过在外层嵌套的方式改变原有渲染
handleClick = () => {console.log('clicked');}
render() {
const otherProps = {handleClick:this.handleClick}
return <WrappedComponent {...this.props} ref={instanceComponent => this.instanceComponent = instanceComponent}/>;
}
}
export default MyContainer//--->这是一个hoc组件
class MyComponent extends Component { ... }
export default MyContainer(MyComponent);
高阶组件可以看做是装饰器模式(Decorator Pattern)在React的实现。即允许向一个现有的对象添加新的功能,同时又不改变其结构,属于包装模式(Wrapper Pattern)的一种
ES7中添加了一个decorator的属性,使用@符表示,上面一行可以改写成@MyContainer
可以在hoc高阶组件中自定义事件,并通过props传递下去,在hoc高阶组件中使用ref,获取当前被包含组件的引用ref