首頁完成效果展現:javascript
<div style="text-align:center;"> <img src="https://img2018.cnblogs.com/blog/1312841/201907/1312841-20190718135309802-1875493361.gif" /> </div>java
1、開發佔位圖組件
在沒有數據的時候使用佔位圖替代 items 的位置。react
在 components 目錄裏建立 moviesItemPlaceholder.jsajax
import React, { Component } from 'react'; import { View, StyleSheet } from 'react-native'; import { px } from '../utils/device'; export default class MoviesItemPlaceholder extends Component { render() { const arr = [1, 2, 3, 4]; return ( <View style={styles.page}> {arr.map((index) => ( <View style={styles.placeholder} key={index}> <View style={styles.img} /> <View style={styles.title} /> <View style={styles.rate} /> </View> ))} </View> ) } } const styles = StyleSheet.create({ page: { flexDirection: 'row', paddingLeft: px(30) }, placeholder: { width: px(160), marginRight: px(16) }, img: { width: px(160), height: px(224), overflow: 'hidden', borderRadius: px(8), backgroundColor: '#f8f8f8' }, title: { marginTop: px(20), backgroundColor: '#f8f8f8', height: px(30), width: px(130), overflow: 'hidden', borderRadius: px(8) }, rate: { marginTop: px(16), backgroundColor: '#f8f8f8', height: px(24), width: px(130), overflow: 'hidden', borderRadius: px(8) } });
2、首頁數據請求
使用 postman 之類的工具能夠看到,首頁接口返回的數據字段大體同樣,數據均在 subject_collection_items 字段裏,能夠瘋轉一個方法量來請求數據。redux
var items = ['showing', 'hot', 'tv', 'variety', 'book', 'music']; items.forEach(type => { this.getList(type); }); getList = (type) => { ajax(type, { start: 0, count: 9 }).then(value => { let state = {} state[type] = value.subject_collection_items; this.setState(state); }) }
首頁頁面展現
縱向滑動,使用 ScrollView 組件;橫向滑動,使用 FlatList 組件,FlatList 組件的 ListEmptyComponent 表示沒有數據時顯示的組件,在這裏放置佔位圖組件;react-native
import React from "react"; import { View, Text, StatusBar, StyleSheet, ScrollView, FlatList, TouchableWithoutFeedback } from "react-native"; import { connect } from 'react-redux'; import ajax from "../utils/ajax"; import Header from '../components/header'; import ItemsHeader from '../components/itemsHeader'; import MoviesItem from '../components/moviesItem'; import MoviesItemPlaceholder from '../components/moviesItemPlaceholder'; import Icon from 'react-native-vector-icons/AntDesign'; import { px } from "../utils/device"; class Home extends React.Component { constructor(props) { super(props); this.state = { showing: [], hot: [], tv: [], variety: [], book: [], music: [], } var items = ['showing', 'hot', 'tv', 'variety', 'book', 'music']; items.forEach(type => { this.getList(type); }); } getList = (type) => { ajax(type, { start: 0, count: 9 }).then(value => { let state = {} state[type] = value.subject_collection_items; this.setState(state); }) } render() { const { dispatch, value, navigation } = this.props; const { showing, hot, tv, variety, book, music } = this.state; const sections = [ { title: '影院熱映', data: showing, type: 'showing' }, { title: '豆瓣熱門', data: hot, type: 'hot' }, { title: '近期熱門劇集', data: tv, type: 'tv' }, { title: '近期熱門綜藝節目', data: variety, type: 'variety' }, { title: '暢銷圖書', data: book, type: 'book' }, { title: '熱門單曲榜', data: music, type: 'music' } ] return ( <View style={styles.page}> <Header showBack={false} title='豆瓣評分' backgroundColor='#00b600' color='#fff' /> <ScrollView> <View style={styles.search}> <TouchableWithoutFeedback onPress={() => alert('search')}> <View style={styles.searchView}> <Icon name='search1' size={px(30)} color='#ccc' /> <Text style={styles.searchText}>搜索</Text> </View> </TouchableWithoutFeedback> </View> {sections.map((list, index) => ( <View key={index} style={styles.list}> <ItemsHeader title={list.title} onPress={() => navigation.push('List', { data: list })} /> <FlatList horizontal={true} data={list.data} keyExtractor={(item, index) => 'item' + index} ListEmptyComponent={() => <MoviesItemPlaceholder />} renderItem={({ item, index }) => ( <View style={{ marginRight: index !== showing.length - 1 ? px(16) : px(30), marginLeft: index === 0 ? px(30) : 0 }}> <MoviesItem data={item} /> </View> )} /> </View> ))} </ScrollView> </View> ); } } const select = (store) => { return { value: store.num.value, } } export default connect(select)(Home); const styles = StyleSheet.create({ page: { flex: 1, backgroundColor: '#fff' }, search: { backgroundColor: '#00b600', height: px(80), alignItems: 'center', justifyContent: 'center' }, searchView: { height: px(50), width: px(710), borderRadius: px(8), backgroundColor: '#fff', flexDirection: 'row', justifyContent: 'center', alignItems: 'center' }, searchText: { fontSize: px(26), color: '#ccc', marginLeft: px(6) }, list: { marginBottom: px(30) } });
4、緩存列表數據
當處於弱網環境時,打開應用,可能會顯示好久的佔位圖,此時咱們能夠將列表數據緩存至本地,每次進入應用先展現本地緩存的數據,而後請求數據,替換本地數據。緩存
此時,就可使用 redux 了。工具
編譯 reducer
爲了目錄整清晰點(讓 redux 相關的代碼文件都存儲於 store 目錄下),將 src 目錄下的 reducer 目錄移動到 store 目錄下,並在 reducer 目錄建立 list.js。post
const initList = { showing: [], hot: [], tv: [], variety: [], book: [], music: [] } const setListState = (state = initList, action) => { switch (action.type) { case 'showing': return { ...state, showing: action.data } case 'hot': return { ...state, hot: action.data } case 'tv': return { ...state, tv: action.data } case 'variety': return { ...state, showing: action.data } case 'book': return { ...state, book: action.data } case 'music': return { ...state, music: action.data } default: return state; } } export default setListState;
在 reducer 的 index.js 中導入 setListState;flex
... import setListState from './list'; ... export default combineReducers({ ... list: setListState ... });
修改 store/index.js 的路徑引入
import reducer from './reducer';
編輯 action
將以前src下的 action 目錄刪除,在 store 目錄下建立 action.js。
export function login(data) { return { type: 'login', data } } export function logout(data) { return { type: 'logout', data } } // set 首頁列表數據 export function setShowing(data) { return { type: 'showing', data } } export function setHot(data) { return { type: 'hot', data } } export function setTv(data) { return { type: 'tv', data } } export function setVariety(data) { return { type: 'variety', data } } export function setBook(data) { return { type: 'book', data } } export function setMusic(data) { return { type: 'music', data } }
編輯首頁
導入修改 store 的方法:
import { setShowing, setHot, setTv, setVariety, setBook, setMusic } from '../store/action';
頁面獲取 store 存儲的數據:
const select = (store) => { return { showing: store.list.showing, hot: store.list.hot, tv: store.list.tv, variety: store.list.variety, book: store.list.book, music: store.list.music } } export default connect(select)(Home);
頁面獲取數據時,改變 store 裏的數據
因爲須要 save 數據,因此前面建立的 getList 和傳入的 items 須要作一些改變:
... var items = [ { type: 'showing', save: setShowing }, { type: 'hot', save: setHot }, { type: 'tv', save: setTv }, { type: 'variety', save: setVariety }, { type: 'book', save: setBook }, { type: 'music', save: setmusic }, ] items.forEach(item => { this.getList(item); }); ... getList = (item) => { ajax(item.type, { start: 0, count: 9 }).then(value => { this.props.dispatch(item.save(value.subject_collection_items)); }) }
修改 render 裏的獲取數據方式:
render(){ const { dispatch, value, navigation, showing, hot, tv, variety, book, music } = this.props; ... }
至此,首頁算是開發完了。