React 數據流動是單向的,父組件向子組件的 通訊也是最多見的方式。父組件經過 props 向子組件傳遞須要的信息html
function EmailInput(props) { return ( <label> Email: <input value={props.email} /> </label> ); } const element = <EmailInput email="123124132@163.com" />; ReactDOM.render( element, document.getElementById('root') );
function EmailInput(props) { return ( <label> Email: <input value={props.email} onChange={props.onChangeEmail} /> </label> ); } class App extends React.Component{ constructor(props){ super(props); this.state = { email: '' } } onChangeEmail(e) => { console.log(e.target.value) this.setState({ email: e.target.value }); } render(){ let { email } = this.state; return ( <EmailInput email={ eamil } onChangeEmail={this.onChangeEmail} />; ) } } ReactDOM.render( <APP />, document.getElementById('root') );
Context 設計目的是爲了共享那些對於一個組件樹而言是「全局」的數據,例如當前認證的用戶、主題或首選語言react
class App extends React.Component { render() { return <Toolbar theme="dark" />; } } function Toolbar(props) { // Toolbar 組件接受一個額外的「theme」屬性,而後傳遞給 ThemedButton 組件。 // 若是應用中每個單獨的按鈕都須要知道 theme 的值,這會是件很麻煩的事, // 由於必須將這個值層層傳遞全部組件。 return ( <div> <ThemedButton theme={props.theme} /> </div> ); } class ThemedButton extends React.Component { render() { return <Button theme={this.props.theme} />; } }
// Context 可讓咱們無須明確地傳遍每個組件,就能將值深刻傳遞進組件樹。 // 爲當前的 theme 建立一個 context(「light」爲默認值)。 const ThemeContext = React.createContext('light'); class App extends React.Component { render() { // 使用一個 Provider 來將當前的 theme 傳遞給如下的組件樹。 // 不管多深,任何組件都能讀取這個值。 // 在這個例子中,咱們將 「dark」 做爲當前的值傳遞下去。 return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } } // 中間的組件不再必指明往下傳遞 theme 了。 function Toolbar() { return ( <div> <ThemedButton /> </div> ); } class ThemedButton extends React.Component { // 指定 contextType 讀取當前的 theme context。 // React 會往上找到最近的 theme Provider,而後使用它的值。 // 在這個例子中,當前的 theme 值爲 「dark」。 static contextType = ThemeContext; render() { return <Button theme={this.context} />; } }
Context 主要應用場景在於不少不一樣層級的組件須要訪問一樣一些的數據。請謹慎使用,由於這會使得組件的複用性變差。使用 context 比較好的場景是真正意義上的全局信息且不會更改,例如界面主題、用戶信息等
若是你只是想避免層層傳遞一些屬性,組件組合(component composition)有時候是一個比 context 更好的解決方案ide
<Page user={user} avatarSize={avatarSize} /> // ... 渲染出 ... <PageLayout user={user} avatarSize={avatarSize} /> // ... 渲染出 ... <NavigationBar user={user} avatarSize={avatarSize} /> // ... 渲染出 ... <Link href={user.permalink}> <Avatar user={user} size={avatarSize} /> </Link>
function Page(props) { const user = props.user; const userLink = ( <Link href={user.permalink}> <Avatar user={user} size={props.avatarSize} /> </Link> ); return <PageLayout userLink={userLink} />; } // 如今,咱們有這樣的組件: <Page user={user} avatarSize={avatarSize} /> // ... 渲染出 ... <PageLayout userLink={...} /> // ... 渲染出 ... <NavigationBar userLink={...} /> // ... 渲染出 ... {props.userLink}
這種對組件組合減小了在你的應用中要傳遞的 props 數量,這在不少場景下會使得你的代碼更加乾淨,使你對根組件有更多的把控。可是,這並不適用於每個場景:這種將邏輯提高到組件樹的更高層次來處理,會使得這些高層組件變得更復雜,而且會強行將低層組件適應這樣的形式,這可能不會是你想要的。函數
並且你的組件並不限制於接收單個子組件。你可能會傳遞多個子組件,甚至會爲這些子組件(children)封裝多個單獨的「接口(slots)」,React 元素本質就是對象(object),因此你能夠把它們看成 props,像其餘數據同樣傳遞。這種方法可能使你想起別的庫中「槽」(slot)的概念,但在 React 中沒有「槽」這一律唸的限制,你能夠將任何東西做爲 props 進行傳遞。this
function Page(props) { const user = props.user; const content = <Feed user={user} />; const topBar = ( <NavigationBar> <Link href={user.permalink}> <Avatar user={user} size={props.avatarSize} /> </Link> </NavigationBar> ); return ( <PageLayout topBar={topBar} content={content} /> ); }