從16年夏天初學React,到17年正式投入到工作中使用,直到現在V16.2發版,React發生了巨大的變化,最近在工作中使用時遇到很多基礎不是非常清晰,藉此再讀React官方文件【中文】。
React核心的單向資料流、一切皆資料的state、不會改變的props,以及狀態提升等等經常使用便不多總結,需要的看官方文件。
JSX
JSX 本質只是為 React.createElement(component, props, …children)提供的語法糖!
- 1.React DOM 在渲染之前都被轉換成了字串,它天生自帶防止 XSS 攻擊的屬性。
- 2.Babel 轉譯器會把 JSX 轉換成一個名為 React.createElement()的方法呼叫。線上babel編譯
以下兩段程式碼等價(許多react的介面設計器通過這個原理,達到後設資料轉化React元素,實現介面化程式設計!)
巢狀就是多個create方法的巢狀。
function hello() {
return <div className="red">Hello,<span>world!</span></div>;
}
"use strict";
function hello() {
return React.createElement(
"div",
{ className: "red" },
"Hello,",
React.createElement(
"span",
null,
"world!"
)
);
}
- 3.JSX中的屬性是可以任何 {} 包裹的 JavaScript 表示式作為一個屬性值,不能使用if和for。
需要迴圈和條件渲染可以使用map、三目,或者使用if/for在jsx程式碼之外!
//錯誤的!
class A extends React.Component {
render() {
return <div>{if(){}else{}}</div>;//原來還矇蔽的不知道為什麼錯了0.0
}
}
React.Component (元件)
建立元件的四種方式:詳情對比參見或者react官網
- React.Component 方式
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
- ES5
var createReactClass = require(`create-react-class`);
var Greeting = createReactClass({
render: function() {
return <h1>Hello, {this.props.name}</h1>;
}
});
//或者使用react
var Greeting = React.create({
render: function() {
return <h1>Hello, {this.props.name}</h1>;
}
});
- 函式式
const Button = ({
day,
increment
}) => {
return (
<div>
<button onClick={increment}>Today is {day}</button>
</div>
)
}
- PureComponet
大多數情況下, 我們使用PureComponent能夠簡化我們的程式碼,並且提高效能,但是PureComponent的自動為我們新增的shouldComponentUpate函式,只是對props和state進行淺比較(shadow comparison),當props或者state本身是巢狀物件或陣列等時,淺比較並不能得到預期的結果,這會導致實際的props和state發生了變化,但元件卻沒有更新的問題。當然還是有解決的方法的,所以建議還是少用。
事件處理
事件繫結的四種方法:推薦使用第一第二種。
class Toggle extends React.Component {
constructor(props) {
{...}
//方法一必須在這裡繫結
this.handleClick1 = this.handleClick.bind(this);
}
handleClick1() {
this...
}
//方法二使用【屬性初始化器語法】【需要開啟babel stage-0以上】
handleClick2=()=> {
this...
}
render() {
return (
<div>
<button onClick={this.handleClick1}></button>
<button onClick={this.handleClick2}></button>
//方法三在使用時繫結
<button onClick={this.handleClick1.bind(this)}></button>
//方法四在回撥函式中使用 箭頭函式
/**
渲染的時候都會建立一個不同的回撥函式。在大多數情況下,這沒有問題。然而如果這個回撥函式作為一個屬性值傳入低階元件,這些元件可能會進行額外的重新渲染。我們通常建議在建構函式中繫結或使用屬性初始化器語法來避免這類效能問題。
**/
<button onClick={(e) => this.handleClick1(e)}></button>
</div>
);
}
}
組合 vs 繼承
在React中不推薦使用繼承,不推薦繼承自定義Component。
//不推薦使用
class Parent extends React.Component {
render() {
return <div>...</div>;
}
}
class A extends Parent {
render() {
return <div>...</div>;
}
}
//推薦使用
class A extends React.Component {
render() {
return <Parent>...</Parent>;
}
}
不使用 ES6
- Component || create
- defaultProps || getDefaultProps
- constructor state || getInitialState
- this bind || 不需要
class Greeting extends React.Component {
constructor(props) {
super(props);
this.state = {count: props.initialCount};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
alert(this.state.message);
}
render() {
return <h1 onClick={this.handleClick}>Hello, {this.props.name}</h1>;
}
}
Greeting.defaultProps = {
name: `Mary`
};
var createReactClass = require(`create-react-class`);
var Greeting = createReactClass({
getInitialState: function() {
return {count: this.props.initialCount};
},
getDefaultProps: function() {
return {
name: `Mary`
};
},
handleClick: function() {
alert(this.state.message);
},
render: function() {
//元件中的方法會自動繫結至例項,不需要像上面那樣加 .bind(this)
return <h1 onClick={this.handleClick}>Hello, {this.props.name}</h1>;
}
});
Refs
- 如果可以通過宣告式實現,則儘量避免使用 refs。
- 不能在函式式元件上使用 ref 屬性,因為它們沒有例項
- 舊版 API:String 型別的 Refs,存在問題,可能會在未來移除,不推薦使用。
- 對父元件暴露refs,在父元素拿子元素
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
class Parent extends React.Component {
//this.inputElement 就是CustomTextInput中的input
render() {
return (
<CustomTextInput
inputRef={el => this.inputElement = el}
/>
);
}
}
ReactDOM
獲取一個DOM除了refs還有更加簡單粗暴的方法findDOMNode
。
findDOMNode 是用於操作底層DOM節點的備用方案。使用它的優先順序比refs更低!!
findDOMNode 只對掛載過的元件有效。
findDOMNode 不能用於函式式的元件中。
import ReactDOM from `react-dom`;
ReactDOM.render(
element,
container,
[callback]//不為人知的第三個引數!!
)
ReactDOM.unmountComponentAtNode(container)
ReactDOM.findDOMNode(component)
不常用的新發現
- 空的 JSX 標籤
Fragments
<></>
或者<React.Fragment></React.Fragment>
- 與運算子
&&
true && expression 總是返回 expression,而 false && expression 總是返回 false。 - 阻止元件渲染常用
null
元件的 render 方法返回 null 並不會影響該元件生命週期方法的回撥。例如,componentWillUpdate 和 componentDidUpdate 依然可以被呼叫。
### 高階元件HOC 使用高階元件(HOC)解決交叉問題