使用import进行代码分割, 异步加载
//使用之前
import { add } from './math';
console.log(add(16, 26));
//使用之后
import("./math").then(math => {
console.log(math.add(16, 26));
});
//使用之前
import OtherComponent from './OtherComponent';
//使用之后
const OtherComponent = React.lazy(() => import('./OtherComponent'));
React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 default export 的 React 组件。
然后应在 Suspense 组件中渲染 lazy 组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级(如 loading 指示器等)。
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
fallback 属性接受任何在组件加载过程中你想展示的 React 元素。你可以将 Suspense 组件置于懒加载组件之上的任何位置。你甚至可以用一个 Suspense 组件包裹多个懒加载组件。
Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
//等同于 空标签
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
显示的 Fragments 支持传递key属性, 其他属性与事件暂时不支持
在大多数情况下,我们推荐使用 受控组件 来处理表单数据。在一个受控组件中,表单数据是由 React 组件来管理的。另一种替代方案是使用非受控组件,这时表单数据将交由 DOM 节点来处理。
要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以 使用 ref 来从 DOM 节点中获取表单数据。
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
ReactDOM.createPortal(child, container)
第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。第二个参数(container)是一个 DOM 元素。
render() {
// React 并*没有*创建一个新的 div。它只是把子元素渲染到 `domNode` 中。
// `domNode` 是一个可以在任何位置的有效 DOM 节点。
return ReactDOM.createPortal(
this.props.children,
domNode
);
}
术语 “render prop” 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术
具有 render prop 的组件接受一个函数,该函数返回一个 React 元素并调用它而不是实现自己的渲染逻辑。
class Cat extends React.Component {
render() {
const mouse = this.props.mouse;
return (
<img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
);
}
}
class Mouse extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
{/*
Instead of providing a static representation of what renders,
use the `render` prop to dynamically determine what to render.
*/ }
{this.props.render(this.state)}
</div>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>移动鼠标!</h1>
<Mouse render={mouse => (
<Cat mouse={mouse} />
)}/>
</div>
);
}
}
重要的是要记住,render prop 是因为模式才被称为 render prop ,你不一定要用名为 render 的 prop 来使用这种模式。事实上, 任何被用于告知组件需要渲染什么内容的函数 prop 在技术上都可以被称为 “render prop”.
尽管之前的例子使用了 render,我们也可以简单地使用 children prop!
(
<p>鼠标的位置是 {mouse.x},{mouse.y}p>
)}/>
//常见问题比如,常见的性能优化方案
思考: 性能优化对于React更加重要?
思考: setState强调的不可变值
shouldComponentUpdate(nextProps,nextState){
if(nextState.count !== this.state.count){
return true //渲染
}
return false //不渲染
}
使用: class Demo extends React.PureComponent
效果: 默认使用SCU中的浅比较
React.Memo就是函数组件中的PureComponent
function Com(props){}
//写一个类似SCU的函数, 传进memo中
function areEqual(prevProps,nextProps){}
export default React.memo(Com,areEqual)
深拷贝性能差
const map1 = Immutable.Map({a:1,b:2})
const map2 = map1.set('b',50)
map1.get('b') //2
map2.get('b') //50