本文是『horseshoe·React專題』系列文章之一,後續會有更多專題推出javascript
來個人 GitHub repo 閱讀完整的專題文章vue
來個人 我的博客 得到無與倫比的閱讀體驗java
React是用來解決狀態同步的,但它卻有一個與this.state
並駕齊驅的概念。react
這就是this.props
。git
this.props
是組件之間溝通的一個接口。github
原則上來說,它只能從父組件流向子組件,可是開發者有各類hack技巧,基本上近親之間溝通是不成問題的。編程
this.props
是一個極其簡單的接口。世界須要更多這樣的傻瓜接口你只須要像寫HTML標籤的屬性同樣,把它寫上去,它就傳到了子組件的this.props
裏面。redux
不過有幾個地方須要注意:框架
ref
和key
,它們各有用途,並不會傳給子組件的this.props
。true
。import React, { Component, createRef } from 'react';
import Child from './Child';
class App extends Component {
isPopular = false;
refNode = createRef();
render() {
return [
<Child key="react" ref={this.refNode} isPopular />,
<Child key="vue" url="https://github.com/vuejs/vue" star={96500} />,
<Child key="angular" owner="google" isPopular={this.isPopular} />,
];
}
}
export default App;
複製代碼
this.props
是一個不可變對象React具備濃重的函數式編程的思想。ide
提到函數式編程就要提一個概念:純函數。
純函數有幾個特色:
function doSomething(a, b) {
return a + b;
}
複製代碼
這是一種編程思想。若是你對這個概念有點模糊,我能夠舉個例子:
你的殺父仇人十年後忽然現身,因而你決定僱傭一個冷麪殺手去解決他。
你會找一個什麼樣的殺手呢?
若是你面對殺父仇人有這樣的覺悟,那麼純函數即是你的囊中之物了。
爲何要提純函數?由於this.props
就是汲取了純函數的思想。
它最大的特色就是不可變。
跟this.state
不同的是,this.props
來真的。雖然this.state
也反對開發者直接改變它的屬性,但畢竟只是嘴上說說,仍是要靠開發者本身的約束。然而this.props
會直接讓你的程序崩潰。
加上React也沒有this.setProps
方法,因此不須要開發者自我約束,this.props
就是不可變的。
這個無需贅言,最直觀的傳值方式。
import React from 'react';
import Child from './Child';
const App = () => {
return (
<Child star={1000} /> ); } export default App; 複製代碼
其實就是利用回調函數的參數傳遞值。
父組件定義一個方法,將該方法經過props傳給子組件,子組件須要給父組件傳值時,便傳參執行該方法。因爲方法定義在父組件裏,父組件能夠接收到該值。
import React, { Component } from 'react';
import Child from './Child';
class App extends Component {
state = { value: '' };
render() {
return (
<Child handleSomething={this.handleSomething} /> ); } handleSomething = (e) => { this.setState({ value: e.target.value }); } } export default App; 複製代碼
import React from 'react';
const Child = (props) => {
return (
<input type="text" onChange={props.handleSomething} /> ); } export default Child; 複製代碼
原理和回調函數同樣,只不過這裏父組件只是一個橋樑。
父組件接收到回調函數的值之後,經過this.setState
保存該值,並觸發另外一個子組件從新渲染,從新渲染後另外一個子組件即可以得到該值。
import React, { Component, Fragment } from 'react';
import ChildA from './ChildA';
import ChildB from './ChildB';
class App extends Component {
state = { value: '' };
render() {
return (
<Fragment>
<ChildA handleSomething={this.handleSomething} />
<ChildA value={this.state.value} />
</Fragment>
);
}
handleSomething = (e) => {
this.setState({ value: e.target.value });
}
}
export default App;
複製代碼
import React from 'react';
const ChildA = (props) => {
return (
<input type="text" onChange={props.handleSomething} /> ); } export default ChildA; 複製代碼
import React from 'react';
const ChildB = (props) => {
return (
<div>{props.value}</div>
);
}
export default ChildB;
複製代碼
👽這是React v16.3.0發佈的API。
React爲開發者提供了一扇傳送門,它就是Context對象。
嚴格來講,Context早就存在於React中了,不過一直以來都不是正式的API。
終於在v16.3.0轉正了。
爲何說Context是一扇傳送門?由於它能夠跨組件傳遞數據。不是父子之間的小打小鬧哦,而是能夠跨任意層級。可是有一個限制,數據只能向下傳遞,緣由就是後面要講到的單向數據流。
開發者經過createContext
建立一個上下文對象(React特別喜歡create),而後找一個頂級組件做爲Provider
。接下來就能夠在任意下級組件消費它提供的數據了。
Provider
的數據改變,就會觸發Consumer
的更新。Provider
的狀況下才起做用。Consumer
的children必須是一個函數。舊的Context存在一個問題,若是接收組件的shouldComponentUpdate
生命週期鉤子返回false,則它不會接收到Context中的數據,由於它是經過this.props
一級一級往下傳的。
而新的Context採起的是訂閱發佈模式,因此不存在這個問題。
實際上react-redux庫的Provider
組件內部就是使用了舊的Context API,不過redux作了一些優化。
import { createContext } from 'react';
const { Provider, Consumer } = createContext({ lang: 'en' });
export { Provider, Consumer };
複製代碼
import React, { Component } from 'react';
import { Provider } from './context';
import Todos from './Todos';
const App = () => {
return (
<Provider value={{ lang: 'zh' }}> <Todos /> </Provider>
);
}
export default App;
複製代碼
import React, { Fragment } from 'react';
import TodoItem from './TodoItem';
const Todos = () => {
return (
<Fragment> <TodoItem /> <TodoItem /> <TodoItem /> </Fragment>
);
}
export default Todos;
複製代碼
import React from 'react';
import { Consumer } from './context';
const TodoItem = () => {
return (
<Consumer> {({ lang }) => <div>{lang === 'en' ? 'todo' : '要作'}</div>} </Consumer>
);
}
export default TodoItem;
複製代碼
水往低處流,這是天然規律。
React經過描述狀態來控制UI的表達,這就涉及到UI的更新機制。
狀態除了內部狀態以外,確定有一些狀態是要組件之間共享的,因此,一旦一個組件的狀態更新了,可能會牽扯到不少組件的更新,框架的更新機制必將變的異常複雜。
可是迴歸到水的意象,若是狀態的流向是單向的,並且是自上往下流動,這就變的很是符合直覺,並且更新機制能夠作到極簡:我更新,則個人全部下級也更新。
這就是this.props
的思想源頭。
它雖然叫props,但它也是狀態,只不過是共享的狀態。
它只能自頂向下流動。
內部不能改變this.props
。
某個props的源頭更新了,則流經的全部組件都要更新,除非開發者手動禁止。
脈絡清晰,this.props
纔是賦予了React血液的東西。
關於React摒棄了表單雙向數據綁定的問題,它只是想把單向數據流作的更完全一點。其實表單的狀態,歸根結底是組件內部的狀態,跟單向數據流無關。
什麼是雙向數據綁定?就是表單輸入,與之綁定的變量自動獲取到輸入的值,變量的值改變,與之綁定的表單的值隨即改變,兩種流向都自動綁定了。
但其實雙向數據綁定不就是value的單向綁定加onChange事件監聽麼!React也能夠經過兩步作到。
總結:雙向數據綁定不影響單向數據流,React也能夠實現雙向的同步。
React專題一覽