核心概念
1. JSX
- JSX是javascript的語法擴展,讓我們可以在JS中編寫常規html代碼,在JSX中可以在大括號
{}
內放置任何有效的javascript表達式。 - JSX也是一個表達式,可以在
if
和for
循環代碼塊中使用JSX。 - 通過引號將屬性值指定為字符串字面量,使用大括號將屬性值指定為j s表達式。
- React DOM 使用
camelCase
(小駝峰命名)來定義屬性的名稱,而不使用 HTML 屬性名稱的命名約定。例如在JSX中class變為className。
const name = 'Jade';
const element = <div>
<h1 className='weclome'>Hello, {name}</h1>
<input type='text' defaultValue={name} />
</div>;
ReactDOM.render(
element,
document.getElementById('root')
);
2. props
- 當 React 元素為用戶自定義組件時,它會將 JSX 所接收的屬性以及子組件轉換為單個對象傳遞給組件,這個對象被稱之為 “props”。
- 組件無論是使用函數聲明還是class聲明,都不能修改自身的 props,props為只讀。
3. State
- state是組件私有化,且完全受控于當前組件,簡單說,完全props,state在組件內可以隨意修改。定義state應該在class構造函數
constructor
中,state可以傳遞給子組件,數據是向下流動。 - 關于修改state,應該使用
setState()
,而不是直接賦值。this.setState({name: 'Jade'}); //correct
this.state.name = 'jade'; // wrong
-
setState()
為異步,多個setState()
會合并為一個調用。所以最好不要依賴它們的值來更新下一個狀態。 - 關于異步的問題,可以讓
setState()
接受一個函數來解決,該函數接受兩個參數,用上一個 state 作為第一個參數,將此次更新被應用時的 props 做為第二個參數。
4. 事件處理
不能通過
return false;
阻止默認行為,只能是e.preventDefault()
。-
JSX中回調問題,事件回調必須綁定
this
,不然回調中this
為undefined
。原因在于js函數工作原理:const obj = { name: 'Jade', say: function () { console.log(this); } }; const test = obj.say; obj.say(); // {name: "Jade", say: ?} test(); // undefined
在js中,傳遞一個函數名給一個變量,然后在變量后加上()調用這個方法,此時方法內部的this的指向就丟失。在React中,OnClick其實就是一個中間變量,所以
this
會丟失。 -
關于事件回調中
this
丟失的解決辦法有以下:- 使用
bind
綁定this
,<a onClick={this.click.bind(this)}>點擊</a>
。 - 使用箭頭函數定義事件回調
this.click = () => { //do something }
- 使用箭頭函數調用事件回調
<a onClick={() => this.click()}>點擊</a>
- 使用
-
事件傳遞參數的方法有兩種,分別是通過箭頭函數和
bind
,事件對象e會被視為第二個參數,不同的是,箭頭函數的方式必須顯式的傳入e,bind
則不需要,如下:<a onClick={(e) => this.click(id, e)}>點擊</a>
<a onClick={this.click.bind(this, id)}>點擊</a>
5. 表單
- 受控組件:表單中存在一個input,其value值必須是我們設置在constructor構造函數中的state的值,通過onChange事件改變state中的值,最終形成一個循環的回路影響。
- 非受控組件:非受控也就意味著我可以不需要設置它的state屬性,而通過ref來操作真實的DOM。
6. 組件之間通訊
-
父子通訊:
// Context 可以讓我們無須明確地傳遍每一個組件,就能將值深入傳遞進組件樹。 // 使用場景: 嵌套多層的組件,且每層組件可能都會用到某個變量 // 缺點:導致組件的復用性降低 const NameContext = React.createContext('Jade'); // 默認值‘Jade’ class App extends React.Component { render() { return ( // 使用Provider,將變量傳遞給下面的所有組件 <NameContext.provider value='Jadeee'> <PageHeader /> </NameContext> ) } } class PageHeader extends React.Component { render() { // 中組件不用在手動傳遞了 return <UserName /> } } class UserName extends React.Component { static contentType = NameContext; render() { return <p> {this.context} </P> } }
// 父子通訊主要通過props傳遞參數,數據自上而下流動,實現父子通訊 class ChildrenComponent extends React.Component { constructor(props) { super(props); } render() { return ( {/* 接受從父組件傳遞而來的title */} <h1> {this.props.title} </h1> ) } } class ParentComponent extends React.Component { constructor(props) { super(props); this.state = { title: '標題' } } render() { return ( {/* 將this.state.title傳遞給子組件 */} <ChildrenComponent title={this.state.title} /> ) } }
-
子父通訊:
class ChildrenComponent extends React.Component { constructor(props) { super(props); this.state = { name: 'children component' } } clickBtn() { // 調用父組件方法并將參數傳遞給父組件 this.props.onClickChildren(this.state.name); } render() { return ( <button type="button" onClick={this.clickBtn.bind(this)}> Click Me! </button> ) } } class ParentComponent extends React.Component { constructor(props) { super(props); } // 子組件調用,val參數為子組件傳遞過來 onClickChildren(val) { console.log(val); // children component } render() { return ( <div> {/* 將onClickChildren()方法作為props傳遞給子組件 */} <ChildrenComponent onClickChildren={this.onClickChildren.bind(this)} /> </div> ) } }
-
子子通訊:
- eventBus
- Redux