React Native 开发豆瓣评分(八)首页开发
程序员文章站
2022-03-20 20:26:51
首页完成效果展示: 一、开发占位图组件 在没有数据的时候使用占位图替代 items 的位置。 在 components 目录里创建 moviesItemPlaceholder.js 二、首頁数据请求 使用 postman 之类的工具可以看到,首页接口返回的数据字段大致一样,数据均在 subject_ ......
首页完成效果展示:
一、开发占位图组件
在没有数据的时候使用占位图替代 items 的位置。
在 components 目录里创建 moviesitemplaceholder.js
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) } });
二、首頁数据请求
使用 postman 之类的工具可以看到,首页接口返回的数据字段大致一样,数据均在 subject_collection_items 字段里,可以疯转一个方法量来请求数据。
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 表示没有数据时显示的组件,在这里放置占位图组件;
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) } });
四、缓存列表数据
当处于弱网环境时,打开应用,可能会显示很久的占位图,此时我们可以将列表数据缓存至本地,每次进入应用先展示本地缓存的数据,然后请求数据,替换本地数据。
此时,就可以使用 redux 了。
编译 reducer
为了目录整清晰点(让 redux 相关的代码文件都存储于 store 目录下),将 src 目录下的 reducer 目录移动到 store 目录下,并在 reducer 目录创建 list.js。
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;
... 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; ... }
至此,首页算是开发完了。
下一篇: ts常用数据类型