花了一周读了React@16的文档和代码(没有读react-dom,找时间读一下),刚开始没想做笔记,后来发现需要记的东西比较多,是以记之。
reactjs.org/docs
属性名使用小驼峰。其中class变为className,tabindex变为tabIndex。
aria-*
、data-*
依然使用小写。(JSX)组件名,在JSX中使用时必须大些(组件传递时可以小写),调用createElement时无需大写。(JSX转createElement时使用小写,会传递字符串标签名作为type;而使用大写时会找到并传递作用域内的同名函数作为type。)(Component in JSX)
props实际上是一个被冻结的对象。(props)
不要直接修改state,不会触发更新机制,使用setState。(state)
state可能是异步的,不要在setState后面同步的取state。(state)
setState支持两个参数,第一个参数是:部分新state 或 一个传入原有state参数并返回部分新state的函数,第二个可选参数是setState完成的回调。(state)
React处理事件使用小驼峰,JSX中传递函数作为事件处理程序,而不是字符串。(Event JSX)
类方法默认没有绑定this,使用this时将会是undefined。(bind)
解决bind的方法有:使用类属性(class-properties)、使用箭头函数回调(每次会生成新的回调函数)、使用autobind工具。(bind)
事件回调函数需要附加参数时
onClick={(e) => this.deleteRow(id)}
与onClick={this.deleteRow.bind(this, id)}
等同,同样会产生新的函数。(bind)不要使用index作为key。如果项目列表顺序可变的话,会导致性能问题和状态异常。(key)
key和ref是特殊props,不会传递到组件代码中,即组件代码无法取用(程序中不能读取,只有React才能读取)。(key ref)
如果需要传递ref属性可以使用其他的属性名,如inputRef。(exposing-dom-refs-to-parent-components)
给受控组件props.value从有效值变为null或者undefined后,组件会保留有效value并允许编辑。(input/textarea/select...)
不建议建立组件的继承层次结构,请使用props和构造(composition)来细化组件职能。(Composition vs Inheritance)
JSX中props中值为true的项可以省略值。(JSX props)
传递props使用扩展语法很容易把不必要的props传递给子组件,而且也不容易维护。(props)
-
true、fasle、null、undefined作为子元素会被忽略,但是0、''(空字符串)会被渲染。(props.children)
- 尤其是ReactNative需要注意0、''。字符串的渲染需要放到组件Text中。使用
&&
表达式进行渲染时,如果前值为0或'',则整个表达式的值为0或'',而一般并不会使用Text组件包裹着,导致错误。
- 尤其是ReactNative需要注意0、''。字符串的渲染需要放到组件Text中。使用
React会在组件Mount、Unmount时调用ref回调,即ref需要生命周期来支持,所以函数式组件不能够接受ref属性。函数式组件内部可以使用ref属性。(refs-and-functional-components)
ref应该定义成类上的bind方法。(定义为内联函数时,更新时会调用两次回调函数,分别传入null释放旧ref、DOM元素设置ref)(refs-and-the-dom#caveats)
在React中,
<input type =“file”/>
总是一个不受控制的组件。它的值只能由用户设置,而不能以编程方式设置。React两个假设:不同类型的元素会产生不同的子树,开发者可以通过key来指明子元素在不同的渲染中保持稳定。(React)
-
绝大多数情况下不需要使用Context,如果你不知道要不要使用Context那就不要使用Context。(Context)
Context是实验性的API,可能被修改或移除。(React@16.3-beta提供了新的Context的API)
Context变更无法像props和state那样通知使用Context的组件进行更新。
如果不熟悉像Redux或MobX这样的状态管理库,请不要使用Context。多数情况下这些库和绑定库已经是很好的选择了。
如果您不是经验丰富的React开发人员,请不要使用Context。
如果坚持使用Context,请隔离到尽可能小的范围,并尽量避免直接使用Context的API以便容易升级。
React@16.2新增Fragment组件,支持返回一组节点。简写
<>...</>
,仅接受key属性。(Fragment)可以使用Portals把子组件挂载到其他位置,但其行为依然像子组件一样。(Portals)
-
错误边界仅捕获子组件树生命周期中的异常。(Error Boundaries)
不包括:
- 事件处理程序
- 异步代码
- 服务器渲染
- 错误边界本身(可以传播到上级错误边界)
React@16开始,未被处理的错误将导致整个React组件树的卸载。(Error)
-
高阶组件(higher-order-components)
- 约定
- 将不相关的props传递给包装组件。
- 最大化组合性。
- 包装显示名以便于调试。
- 注意事项
- 不要在render中使用高阶组件。(每次渲染创建一个新版本的高阶组件,不仅仅是性能问题,组件状态将无法保持)
- 必须复制静态方法。(比如使用库hoist-non-react-statics进行复制,或者将静态方法和组件本身分开导出)
- 避免对高阶组件使用ref。(或者参考
14.
使用替代的名字,但这不是最好的解决方案。)
- 约定
渲染属性是使一个组件知道如何去渲染的函数,一些情况下能够很好的解耦。另外可以使用带有渲染属性的常规组件来实现大多数高阶组件。(render-props)
-
代码分割(感觉基于webpack的代码分割更现实)(Code-Splitting)
- 动态import
- react-loadable和基于路由的react-loadable
在componentWillMount中调用setState不会产生额外的渲染。在componentDidMount中调用setState会在浏览器更新屏幕之前触发一次额外的渲染,用户虽然看不到,但是可能会有性能问题,常用于渲染依赖于大小或位置的内容之前测量DOM节点。(Component Lifecycle)
-
shouldComponentUpdate返回false(Component Lifecycle)
- 会阻止组件以及子组件更新props和重渲染,直到下次render。
- 不会阻止组件state数据更新(只是不进行重渲染)。
- 不会阻止子组件因其state发生变化而重新渲染。
shouldComponentUpdate中进行props和state比较时不要使用JSON.stringify,非常影响性能。(Component Lifecycle and Performance)
事件对象是被池化的、跨浏览器的封装对象,可以使用nativeEvent获取原始的事件对象。不要直接引用事件对象,它可能会意外被清空。如有必要请使用
event.persist()
从池中移除并允许用户持有事件对象。(SyntheticEvent)事件处理程序返回false不会停止事件传播,可以手动使用
e.stopPropagation()
和e.preventDefault()
阻止事件冒泡和默认的事件处理行为。(SyntheticEvent)关于注释,标签外可以使用JS风格注释,标签内可以使用
{/* ... */}
风格注释,但是会生成空节点,即{undefined}
,尽管不会渲染,但是在一些仅支持一个子节点的组件下会报错,比如Touch类的部分组件。