現在的 hourlyWeather
資料只有顯示 4 筆,感覺可以顯示更多,所以我們來使用 FlatList
來顯示更多資料。
FlatList
是 React Native 中用來顯示列表的元件,它的使用方式跟 React 中的 map
類似,都是將資料轉換成元件,然後顯示在畫面上。
使用 FlatList
的好處是,它可以只顯示畫面上可見的元件,而不是將所有元件都渲染出來,這樣可以節省記憶體,並且提升效能。
在 App.tsx
中,使用 FlatList
來顯示 hourlyWeather
:
import { View, SafeAreaView, ScrollView, FlatList } from 'react-native'
// 省略其他程式碼
export default function App() {
// 省略其他程式碼
return (
<SafeAreaView className='flex-1 bg-blue-500'>
<StatusBar style='auto' />
<HeaderInfo />
<CurrentWeather />
<View className='flex-row py-6'>
<FlatList
data={hourlyWeather}
keyExtractor={({ dt }) => dt.toString()}
renderItem={({ item }) => {
const { temp, readableTime } = item
return (
<HourlyForecast time={readableTime} icon='cloudy' temp={temp} />
)
}}
horizontal
/>
</View>
// 省略其他程式碼
</SafeAreaView>
)
}
記得加上 horizontal
,這樣 FlatList
才會水平顯示。
不過看一下畫面,會發現裡面的元件並沒有按照螢幕的寬度平均分配。
useWindowDimensions
是 React Native 提供的 Hook,可以取得螢幕的寬度與高度,我們可以使用它來設定 FlatList
的 width
。這在 React Native 中是很常見的做法,因為螢幕的寬度不一定是固定的,所以我們需要使用 useWindowDimensions
來取得螢幕的寬度,然後再設定給 FlatList
。
import {
View,
SafeAreaView,
ScrollView,
FlatList,
useWindowDimensions
} from 'react-native'
// 省略其他程式碼
export default function App() {
// 省略其他程式碼
const windowWidth = useWindowDimensions().width
const itemWidth = windowWidth / 4
return (
<SafeAreaView className='flex-1 bg-blue-500'>
<StatusBar style='auto' />
<HeaderInfo />
<CurrentWeather />
<View className='flex-row py-6'>
<FlatList
data={hourlyWeather}
keyExtractor={({ dt }) => dt.toString()}
renderItem={({ item }) => {
const { temp, readableTime } = item
return (
<View style={{ width: itemWidth }}>
<HourlyForecast time={readableTime} icon='cloudy' temp={temp} />
</View>
)
}}
horizontal
/>
</View>
// 省略其他程式碼
</SafeAreaView>
)
}
這裡我們使用 useWindowDimensions
取得螢幕的寬度,然後將寬度除以 4,這樣就可以得到每個元件的寬度,最後設定給 FlatList
中的元件。
這樣畫面就會顯示正常比例了。
接下來設定顯示筆數為 24 筆,這樣就可以顯示未來一天的天氣預報了。
// src/store/index.ts
const convertHourlyToReadableTime = (
hourlyData: HourlyWeatherInfo[],
sliceCount: number = 25
) => {
return hourlyData.slice(1, sliceCount).map((hour: HourlyWeatherInfo) => {
const readableTime = dayjs.unix(hour.dt).format('HH:mm')
return { ...hour, readableTime }
})
}
雖然現在可以顯示未來一天的天氣預報,不過在終端機也出現一些警告訊息:
LOG VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders components that follow React performance best practices like PureComponent, shouldComponentUpdate, etc. {"contentLength": 2358, "dt": 3517, "prevDt": 13971}
當看到這個訊息時,代表目前的效能不是很好,這通常出現在渲染大量元件時,所以我們需要優化一下。
在 App.tsx
中,我們可以將 FlatList
中的元件抽出來,然後使用 React.memo
來優化:
import { useEffect, memo } from 'react'
// 省略其他程式碼
export default function App() {
// 省略其他程式碼
const MemoizedHourlyForecast = memo(HourlyForecast)
return (
<SafeAreaView className='flex-1 bg-blue-500'>
<StatusBar style='auto' />
<HeaderInfo />
<CurrentWeather />
<View className='flex-row py-6'>
<FlatList
data={hourlyWeather}
keyExtractor={({ dt }) => dt.toString()}
renderItem={({ item }) => {
const { temp, readableTime } = item
return (
<View style={{ width: itemWidth }}>
<MemoizedHourlyForecast time={readableTime} icon='cloudy' temp={temp} />
</View>
)
}}
horizontal
/>
</View>
// 省略其他程式碼
</SafeAreaView>
)
}
這樣就不會出現警告訊息了,並且功能一切正常👍。