在 React 中我們時常會透過元件化,來增加程式碼的重用性,提升易維護性。舉例來說,好幾頁都會出現的搜尋欄、分類 tab 等,就可以拆成元件,再像積木一樣在需要的地方插入。同時當搜尋欄壞掉時,我們也可以直接開啟該檔案修護,不需要在不同頁面、幾百行程式碼中尋找哪行在寫搜尋欄的邏輯?又是哪行壞掉了?
馬上進入實做部分。我們已經有第一個元件 App.jsx 了,現在仿照他的架構,來建立第二個元件 Child.jsx 。習慣上會在根目錄建立 components 資料夾放檔案,統一管理所有元件。再次提醒,元件要以大寫開頭命名!
import React from 'react';
import {View, Text} from 'react-native';
function Child() {
return (
<View>
<Text>子元件</Text>
</View>
);
}
export default Child;
透過 import 引入元件,接著使用上就和 <View>
等元件相同,擺在對應位置即可。以下方例子來說,當 App 元件引入 Child , Child 就成了 App 的子元件, App 則是 Child 的父元件。
import Child from './components/Child';
function App() {
return (
<SafeAreaView>
<View>
<Child />
</View>
</SafeAreaView>
);
}
export default App;
上述的情景是最單純的一種,不過實務上我們會遇到一些彼此長得 87% 像的東西,偏偏就是有那 13% 的不同。若為了那一點點不同,分好幾個元件,似乎又喪失元件化的初衷。以 Google 首頁下方會出現的捷徑來說,不要跟我說你想把這些拆成十個元件… 那還不如不要拆…
所以我們就會面臨一個問題,怎樣讓同一個元件顯示不同圖片和文字? Props會是這個問題的其中一個解答,他的作用是幫助資料單向從父元件傳進子元件。寫法是將要在子元件使用的名稱放前面,父元件要傳入的資料名稱放後面:
function App() {
const [parentText, setParentText] = useState('父元件傳進來的文字');
return (
<Child text={parentText} />
子元件則用下面的方式引入資料:
function Child({text}) {
return (
<View>
<Text>子元件</Text>
<Text>{text}</Text>
</View>
);
}
當然,多引入幾個元件也沒問題。
<Child text={parentText}/>
<Child text="另一個子元件"/>
Tips :稍微補充一下引入資料的寫法演變,最直觀的寫法其實是這樣:
function Child(props) { // 傳入的值一率被 props 這個物件包住
return (
{/* 而要取用 props 物件裡的值就要用在父元件取的名稱 */}
<Text>{props.text}</Text>
);
}
不過有了 ES6 的物件解構,我們不用打這麼多字,直接在小括弧指定我們要的屬性名稱就能使用了。
function Child({text}) {
// {text} 等於直接取用 props.text
return (
<Text>{text}</Text>
);
}
Props 有一點要注意的,誠如前面所說,他是從父元件單向傳到子元件。換句話說不能從子元件反向傳資料回父元件,再說得更明確一點,我們不能直接去更改 Props 的值。 Props 只是一扇窗,讓子元件能顯示父元件的東西。這是為了避免子元件和父元件各自更新後不一致,產生意料之外的副作用。
要改變在子元件 Props 顯示的內容,唯一方法是父元件的資料被改變了,再藉由 Props 把改變後的內容傳給子元件,使子元件跟著被改變。
以先前的 App 、 Child 來示範,就像下方這樣:
function App() {
const [parentText, setParentText] = useState('父元件傳進來的文字');
const handlePress = () => {
setParentText('父元件傳進來的文字改變了');
};
return (
<Child text={parentText} onPress={handlePress} />
function Child({text, onPress}) {
return (
<View>
<Text>子元件</Text>
<Text>{text}</Text>
<TouchableOpacity onPress={onPress}>
<Text>按下後改變 text</Text>
</TouchableOpacity>