• React Native 开发豆瓣评分(八)首页开发


    首页完成效果展示:

    一、开发占位图组件

    在没有数据的时候使用占位图替代 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: {
             px(160),
            marginRight: px(16)
        },
        img: {
             px(160),
            height: px(224),
            overflow: 'hidden',
            borderRadius: px(8),
            backgroundColor: '#f8f8f8'
        },
        title: {
            marginTop: px(20),
            backgroundColor: '#f8f8f8',
            height: px(30),
             px(130),
            overflow: 'hidden',
            borderRadius: px(8)
        },
        rate: {
            marginTop: px(16),
            backgroundColor: '#f8f8f8',
            height: px(24),
             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),
         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;
        ...
    }
    

    至此,首页算是开发完了。

  • 相关阅读:
    GoldenGate Studio 12.2.1.1发布
    重构-改善既有代码的设计完整笔记系列之8
    重构-改善既有代码的设计完整笔记系列之6、7
    Java多线程开发系列-线程管理
    Java多线程开发系列-线程活性故障
    Java多线程开发系列-线程间协作
    Java多线程开发系列-基础
    了不起的Java-CompletableFuture组合异步编程
    了不起的Java-Optional替代null处理
    了不起的Java-Lambda替代设计模式
  • 原文地址:https://www.cnblogs.com/hl1223/p/11214488.html
Copyright © 2020-2023  润新知