React 16其实已经出来了大半年了,作为一个前端从业者,深深为自己的技术迟钝感到愧疚。
最近同事讨论的比较多,好奇心驱使下看了下react的文档,现学现卖,分享如下:(示例代码大部分摘抄自React Posts, 原文链接)
1. Fragment
Fragment 是 16.0加入的新特性,在16.2中获得了升级。
在之前的React中,如果我们要在一个Component里面render诸如以下的view
Some text.
<h2>A heading</h2>
More text.
<h2>Another heading</h2>
Even more text.
那么我们只能用下面的方法:
render() {
return (
<div>
Some text.
<h2>A heading</h2>
More text.
<h2>Another heading</h2>
Even more text.
</div>
);
}
这样导致的问题是,无论我们需不需要,render出的真正的HTML DOM上会多出一个<div>或者<span>
为了解决这个问题,React16.0提供了在render方法中返回array的功能,现在代码可以写成这样:
render() {
return [
"Some text.",
<h2 key="heading-1">A heading</h2>,
"More text.",
<h2 key="heading-2">Another heading</h2>,
"Even more text."
];
}
然而我们还是不满意,这个写法太不JSX了,所以提供了Fragment这个Component来解决问题(所以你需要import {Fragment} from 'react'
啦)
render() {
return (
<Fragment>
Some text.
<h2>A heading</h2>
More text.
<h2>Another heading</h2>
Even more text.
</Fragment>
);
}
还有更简单的写法(为了编译通过你可能需要一些babel的支持)
render() {
return (
<>
Some text.
<h2>A heading</h2>
More text.
<h2>Another heading</h2>
Even more text.
</>
);
}
这样我们真正render出的HTML DOM结构里就不存在不需要的<div>或者<span>了
2. Render Props
Render Props可以作为一种新的HOC的写法(见下例),官方给的例子是一个track鼠标位置的component和一个show图片的component:
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 MouseWithCat 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: '100%' }} onMouseMove={this.handleMouseMove}>
{/*
We could just swap out the <p> for a <Cat> here ... but then
we would need to create a separate <MouseWithSomethingElse>
component every time we need to use it, so <MouseWithCat>
isn't really reusable yet.
*/}
<Cat mouse={this.state} />
</div>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>Move the mouse around!</h1>
<MouseWithCat />
</div>
);
}
}
定义了MouseWithCat
这样一个Component
来 Handle Mouse Tracking
这一事件,把track到的x,y坐标放到下一层Cat的mouse这个props上,这是我们之前的一种写法。
现在拥有了Render Props后,我们可以这样写:
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: '100%' }} onMouseMove={this.handleMouseMove}>
{/*
Instead of providing a static representation of what <Mouse> 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>Move the mouse around!</h1>
<Mouse render={mouse => (
<Cat mouse={mouse} />
)}/>
</div>
);
}
}
注意Mouse的Render方法中调用的this.props.render, 和我们在MouseTracker中传给Mouse的render方法。
代码展开一下,实际上是我们在Mouse的render方法中调用了我们给Mouse.props传递的render方法,这个render方法接受一个mouse参数,并且返回一个Cat Component, 这个Cat Component接受mouse这个参数,并且在鼠标显示的位置显示一张图片。
使用这个特性的好处很明显,我们不需要MouseWithCat这个Component了,现在Mouse和Cat是两个独立的component,而且我们可以给Mouse传入其他的render参数,比如<Mouse render={mouse=>(<Doge mouse={mouse}></Doge>)}>
,而不用再创建一个MouseWithDog
但这个特性其实和这种写法效果相似:
const withMouse = (Component) => ({mouse}) {
//some code
return <Component mouse={mouse} />
}
调用的时候我们先创建一个MouseWithCat变量:
const MouseWithCat = withMouse(Cat);
<MouseWithCat mouse={mouse} />
在效果上来说,都把Mouse和Cat这两个Component解绑了,但有了render props支持后,写法更简洁了。
另外withMouse这个Higher Order Component
,也可以使用Render Props:
function withMouse(Component) {
return class extends React.Component {
render() {
return (
<Mouse render={mouse => (
<Component {...this.props} mouse={mouse} />
)}/>
);
}
}
}
Render Props的render和我们Component的render是两个不同的东西,不要弄混
了。实际上,只是这种写法叫做Render props, 这里只是为了方便理解起了个名字叫render, 我们还可以叫它abc
,在Component中调用的时候使用this.props.abc
。
叫children也可以。
<Mouse children={mouse => (
<p>The mouse position is {mouse.x}, {mouse.y}</p>
)}/>
再简化:
<Mouse>
{mouse => (
<p>The mouse position is {mouse.x}, {mouse.y}</p>
)}
</Mouse>
这就是一种FACC(Function As Child Component)了