React常用的api
PureComponent
React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实现 shouldComponentUpdate(),而 React.PureComponent 中以浅层对比 prop 和 state 的方式来实现了该函数。
首先我们来看个例子
import React, { Component, PureComponent } from "react";
class App extends Component {
state = {
count: [0, 1],
len: 2,
};
render() {
const { count, len } = this.state;
return (
<>
<button
onClick={() => {
this.setState({ count: [...count, len + 1], len: len + 1 });
}}
>
+
</button>
{count.map((item, index) => (
<Child data={item} key={index} />
))}
</>
);
}
}
class Child extends Component {
render() {
const { data } = this.props;
console.log(data);
return <div>{data}</div>;
}
}
export default App;
在这个例子中,我们只对count进行修改,看下另一个组件会发生什么
可以看到我们对count进行了修改,但是子组件全部重新渲染了,这并不是我们想要的。这时候我们可以使用PureComponent进行改写,只对新增的<Child/>进行重新渲染
class Child extends PureComponent {
render() {
const { data } = this.props;
console.log(data);
return <div>{data}</div>;
}
}
可以看到,只有count变化了的组件才重新渲染,这无疑提高了性能。
当然我们也可以用shouldComponentUpdate进行手动优化。
class Child extends Component {
shouldComponentUpdate(prevProps, prevState) {
// return true时,执行更新,return false不执行更新
return prevProps === this.props;
}
render() {
const { data } = this.props;
console.log(data);
return <div>{data}</div>;
}
}
Ref
下面是几个适合使用 refs 的情况:
- 管理焦点,文本选择或媒体播放。
- 触发强制动画。
- 集成第三方 DOM 库。 Refs 提供了一种方式,允许我们访问DOM 节点或在 render 方法中创建的React 元素。
ref 的值根据节点的类型而有所不同:
- 当 ref 属性用于
HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性。 - 当 ref 属性用于
自定义 class 组件时,ref 对象接收组件的挂载实例作为其current属性。 - 你不能在函数组件上使用 ref 属性,因为他们没有实例。
Ref用于html元素
接下来举个例子,通过双击p标签展示input标签并自动聚焦
import React, { Component } from "react";
class App extends Component {
state = {
msg: "hello world",
textInput: React.createRef(),
showInput: false,
};
focusTextInput = () => {
// 更新完showInput之后再执行聚焦,因为setState并非同步的
this.setState({ showInput: true }, () => {
this.state.textInput.current.focus();
});
console.log(this.state.textInput.current);
};
render() {
const { msg, textInput, showInput } = this.state;
const display = showInput ? "block" : "none";
return (
<>
{/* 双击后显示输入框 */}
<p onDoubleClick={this.focusTextInput}>{msg}</p>
{/* 失去焦点后不显示输入框 */}
<input
type="text"
ref={textInput}
value={msg}
style={{ display: display }}
onChange={(e) => {
this.setState({ msg: e.target.value });
}}
onBlur={() => {
this.setState({ showInput: false });
}}
/>
</>
);
}
}
export default App;
Result:
Ref用于自定义class组件
import React, { Component } from "react";
class App extends Component {
state = {
textInput: React.createRef(),
};
componentDidMount() {
console.log(this.state.textInput.current);
}
render() {
const { textInput } = this.state;
return (
<>
<Child ref={textInput} />
</>
);
}
}
class Child extends Component {
render() {
return (
<>
<p>I m Child</p>
</>
);
}
}
export default App;
Result:
回调Ref
React 也支持另一种设置 refs 的方式,称为“回调 refs”。它能助你更精细地控制何时 refs 被设置和解除。
不同于传递 createRef() 创建的 ref 属性,你会传递一个函数。这个函数中接受 React 组件实例或 HTML DOM 元素作为参数,以使它们能在其他地方被存储和访问。
接下来的例子,通过点击focus按钮,可以聚焦到input输入框
import React, { Component } from "react";
class App extends Component {
selectEl = null;
render() {
return (
<>
<button
onClick={() => {
this.selectEl && this.selectEl.focus();
}}
>
focus
</button>
<input
ref={(node) => {
this.selectEl = node;
console.log(node);
}}
/>
</>
);
}
}
export default App;
Result:
Children
每个组件都可以获取到 props.children。它包含组件的开始标签和结束标签之间的内容。
import React, { Component } from "react";
class App extends Component {
selectEl = null;
render() {
return (
<>
<div>我是App</div>
<Child>
<div>我是传过去的1</div>
</Child>
</>
);
}
}
function Child(props) {
console.log(props);
return (
<>
<div>我是Child</div>
{props.children}
</>
);
}
export default App;
Result:
如果我们传的内容是多个节点呢?
import React, { Component } from "react";
class App extends Component {
selectEl = null;
render() {
return (
<>
<div>我是App</div>
<Child>
<div>我是传过去的1</div>
<div>我是传过去的2</div>
<div>我是传过去的3</div>
</Child>
</>
);
}
}
function Child(props) {
console.log(props);
return (
<>
<div>我是Child</div>
{props.children}
</>
);
}
export default App;
dangerouslySetInnerHTML
有时候我们有这么个需求,直接把一段html代码给显示出来
import React, { Component } from "react";
class App extends Component {
state = {
data: `<h1>Hello, world</h1>`,
};
render() {
const { data } = this.state;
return (
<>
<div>我是App</div>
{data}
</>
);
}
}
export default App;
可以看到,react并没有把data当成html来解析。如果换成原生的js的话,我们可以直接设置el.innerHTML=data。在React中,也提供了类似的api,dangerouslySetInnerHTML。
dangerouslySetInnerHTML 是 React 为浏览器 DOM 提供 innerHTML 的替换方案。通常来讲,使用代码直接设置 HTML 存在风险,因为很容易无意中使用户暴露于跨站脚本(XSS)的攻击。因此,你可以直接在 React 中设置 HTML,但当你想设置 dangerouslySetInnerHTML 时,需要向其传递包含 key 为 __html 的对象,以此来警示你.
import React, { Component } from "react";
class App extends Component {
state = {
data: `<h1>Hello, world</h1>`,
};
render() {
const { data } = this.state;
return (
<>
<div>我是App</div>
<div dangerouslySetInnerHTML={{ __html: data }}></div>
</>
);
}
}
export default App;