Authored by shangjf

首页业务逻辑优化 review by 陈林

'use strict';
import React from 'react';
import ReactNative from 'react-native';
import Immutable, {Map} from 'immutable';
const {
View,
Text,
ListView,
TouchableOpacity,
Dimensions,
StyleSheet,
Platform,
} = ReactNative;
export default class ChannelSelector extends React.Component {
constructor(props) {
super (props);
this._renderRow = this._renderRow.bind(this);
this._renderSeparator = this._renderSeparator.bind(this);
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1.id != r2.id,
});
}
shouldComponentUpdate(nextProps){
if (nextProps.onSelectdIndex == this.props.onSelectdIndex) {
return false;
} else {
return true;
}
}
_renderRow(rowData, sectionID, rowID) {
let isRowSelected = false;
let onSelectdIndex = this.props.onSelectdIndex;
let dataSource = this.props.dataSource;
isRowSelected = onSelectdIndex == rowID;
let colorStyle = isRowSelected ? {color: '#444444', fontFamily: 'HelveticaNeue', fontSize: 17} : {color: '#b0b0b0', fontFamily: 'HelveticaNeue', fontSize: 17,};
let rowWidth = width/dataSource.length;
return (
<TouchableOpacity activeOpacity={1} onPress={() => {
if (isRowSelected) {
return;
}
this.props.onClickSort && this.props.onClickSort(rowID);
}}>
<View key={'row' + rowID} style={[styles.rowContainer, {width: rowWidth}]}>
<Text style={[styles.name, colorStyle]}>{rowData}</Text>
</View>
</TouchableOpacity>
);
}
_renderSeparator(sectionID, rowID, adjacentRowHighlighted) {
return (
<View key={'sep' + rowID} style={styles.separator}>
</View>
);
}
render() {
let {dataSource} = this.props;
dataSource = dataSource ? dataSource : [];
return (
<View style={styles.container}>
<ListView
contentContainerStyle={styles.contentContainer}
enableEmptySections={true}
dataSource={this.dataSource.cloneWithRows(dataSource)}
renderRow={this._renderRow}
renderSeparator={this._renderSeparator}
scrollEnabled={false}
scrollsToTop={false}
/>
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let viewHeight = 44;
let styles = StyleSheet.create({
container: {
width: width,
height: viewHeight,
borderTopColor: 'transparent',
borderBottomColor: '#e0e0e0',
borderBottomWidth: 0.5,
backgroundColor:'white',
},
contentContainer: {
flexDirection: 'row',
},
rowContainer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
height: viewHeight,
backgroundColor:'white',
},
name: {
color: '#b0b0b0',
},
separator: {
width: 0.5,
top: 14,
height: 16,
backgroundColor: '#e0e0e0',
},
});
... ...
... ... @@ -16,8 +16,9 @@ import ReactNative, {
} from 'react-native';
import Immutable, {Map} from 'immutable';
import LoadMoreIndicator from '../../../common/components/LoadMoreIndicator';
import YH_SortView from '../../../common/components/YH_SortView';
import HeadTitleCell from '../cell/HeadTitleCell';
import channelTransfer from '../../../common/utils/channelTransfer';
import floorParser from '../../utils/floorParser';
import Focus from '../floor/Focus';
import AppIconList from '../floor/AppIconList';
... ... @@ -56,6 +57,7 @@ export default class Home extends Component {
this.trigggePullToRefresh = this.trigggePullToRefresh.bind(this);
this._floorCellRender = this._floorCellRender.bind(this);
this._currentChannelData = this._currentChannelData.bind(this);
this._renderSectionHeader = this._renderSectionHeader.bind(this);
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => !Immutable.is(r1, r2),
... ... @@ -133,8 +135,19 @@ export default class Home extends Component {
);
}
case 'lifeStyleFav': {
return null;
}
let paddingLeft = rowID % 2 == 1 ? rowMarginHorizontal*1.5 : rowMarginHorizontal*2;
let customStyle = {paddingLeft};
return (
<View style={[styles.product,]}>
<ProductListCell
style={[styles.listContainer, customStyle]}
key={'row' + rowID}
rowID={rowID}
data={rowData}
onPressProduct={this.props.onPressProductListProduct}
/>
</View>
); }
break;
default:
{
... ... @@ -377,8 +390,10 @@ export default class Home extends Component {
_renderFooter() {
let data = this._currentChannelData();
let {isFetching, endReached, list} = data;
let isLoadingMore = !endReached && list.size != 0;
let {isFetching, endReached, list, cached} = data;
let floorList = list.size > 0 ? list.toArray() : cached.get('list').toArray();
let isLoadingMore = !endReached && floorList.size != 0;
return (
<LoadMoreIndicator
isVisible={isLoadingMore}
... ... @@ -388,12 +403,17 @@ export default class Home extends Component {
}
_renderSectionHeader(sectionData, sectionID) {
let floor = [];
if (sectionID == 'floor') {
floor = sectionData;
}
if (sectionID == 'lifeStyleFav') {
let data = this._currentChannelData();
let selectIndex = data.selectIndex;
selectIndex = parseInt(selectIndex);
return (
<YH_SortView
dataSource={['新品到着', '人气单品']}
onSelectdIndex={selectIndex}
onClickSort={this.props.onClickSort}
/>
);
}else {
return null
}
... ... @@ -402,43 +422,8 @@ export default class Home extends Component {
render() {
let channel = this.props.channel;
let data = this._currentChannelData();
let {list, cached, isFetching, isFirstLoad, endReached, favorite, bottomBanner, hotList, newList} = data;
let floorList = list.size > 0 ? list.toArray() : cached.get('list').toArray();
let dataSource = {};
if (channel == 4) {
dataSource = {
floor: floorList,
lifeStyleFav:{
hotList,
newList
}
}
} else {
let favoriteList = favorite.get('list');
let bottomBannerList = bottomBanner.get('list');
if (favoriteList.size == 0) {
dataSource = {
floor: floorList,
}
}else {
if (favoriteList.size > 0 && endReached) {
dataSource = {
floor: floorList,
favoriteHeader: ['1'],
favorite: favoriteList.toArray(),
bottomBanner: [bottomBannerList],
footer: ['1']
}
}else {
dataSource = {
floor: floorList,
favoriteHeader: ['1'],
favorite: favoriteList.toArray()
}
}
}
}
let {isFetching} = data;
let dataSource = floorParser.homeDataParse(data, channel);
let isPullToRefresh = isFetching;
... ...
... ... @@ -9,7 +9,7 @@ export default keyMirror({
HOME_RESET_STATE_WHEN_REFRESH: null,
HOME_FLOOR_DATA_HAS_NOT_CHANGE: null,
LOAD_CHANNEL_CACHED_DATA: null,
HOME_FLOOR_REQUEST: null,
... ... @@ -28,6 +28,8 @@ export default keyMirror({
HOME_LIFESTYLE_FAVORITE_SUCCESS: null,
HOME_LIFESTYLE_FAVORITE_FAILURE: null,
HOME_LIFESTYLE_FAVORITE_SET_INDEX: null,
HOME_SHOP_INFO_REQUEST: null,
HOME_SHOP_INFO_SUCCESS: null,
HOME_SHOP_INFO_FAILURE: null,
... ...
... ... @@ -68,6 +68,7 @@ class HomeContainer extends Component {
this.onPressShopRecommendItem = this.onPressShopRecommendItem.bind(this);
this.onPressShopFavorite = this.onPressShopFavorite.bind(this);
this.onPressTitleMore = this.onPressTitleMore.bind(this);
this.onClickSort = this.onClickSort.bind(this);
this.subscription = NativeAppEventEmitter.addListener(
'ChannelDidChangeEvent',
... ... @@ -166,7 +167,7 @@ class HomeContainer extends Component {
}
onPressShopFavorite(shopId, index) {
console.log(shopId)
}
onPressBrandItem(url, index) {
... ... @@ -186,6 +187,10 @@ class HomeContainer extends Component {
this.jumpWithUrl(url);
}
onClickSort(index) {
this.props.actions.selecLifeStyleProductIndex(index);
}
render() {
let {app, home} = this.props;
return (
... ... @@ -216,6 +221,7 @@ class HomeContainer extends Component {
onPressShopRecommendItem={this.onPressShopRecommendItem}
onPressShopFavorite={this.onPressShopFavorite}
onPressTitleMore={this.onPressTitleMore}
onClickSort={this.onClickSort}
/>
</View>
);
... ...
... ... @@ -27,6 +27,8 @@ const {
HOME_LIFESTYLE_FAVORITE_SUCCESS,
HOME_LIFESTYLE_FAVORITE_FAILURE,
HOME_LIFESTYLE_FAVORITE_SET_INDEX,
HOME_SHOP_INFO_REQUEST,
HOME_SHOP_INFO_SUCCESS,
HOME_SHOP_INFO_FAILURE,
... ... @@ -156,7 +158,7 @@ export function fetchBoyGirlFavoriteList() {
if (currentChannelData.favorite.isFetching
|| currentChannelData.endReached
|| currentChannelData.list.size == 0) {
|| (currentChannelData.list.size == 0 && currentChannelData.cached.get('list').size == 0)) {
return;
}
... ... @@ -222,7 +224,7 @@ export function fetchKidsFavoriteList() {
let {kid} = home;
if (kid.favorite.isFetching
|| kid.endReached
|| kid.list.size == 0) {
|| (kid.list.size == 0 && kid.cached.get('list').size == 0)) {
return;
}
... ... @@ -236,7 +238,7 @@ export function fetchKidsFavoriteList() {
.then(json =>{
let payload = floorParser.parseKidsFavorite(json);
if (payload.currentPage > 1) {
let oldList = kid.favorite.list.toJS();
let oldList = kid.favorite.get('list').toJS();
let newList = [...oldList, ...payload.list];
payload.list = newList;
}
... ... @@ -275,8 +277,7 @@ function fetchLifeStyleFavoriteList(fromPage) {
let {lifeStyle} = home;
if (lifeStyle.isListFetching
|| lifeStyle.endReached
|| lifeStyle.list.size == 0) {
|| (lifeStyle.list.size == 0 && lifeStyle.cached.get('list').size == 0)) {
return;
}
... ... @@ -308,6 +309,19 @@ function fetchLifeStyleFavoriteList(fromPage) {
}
}
export function selecLifeStyleProductIndex(index) {
return (dispatch) => {
dispatch(selectLifeStyleIndex(index));
}
}
function selectLifeStyleIndex(index) {
return {
type: HOME_LIFESTYLE_FAVORITE_SET_INDEX,
payload: index
}
}
/**
** 男女频道底部banner
**/
... ...
... ... @@ -60,6 +60,8 @@ let lifeStyle = new (Record({
listError: null,
hotList: List(), //创意生活频道 人气单品商品列表
newList: List(), //创意生活频道 新品到着商品列表
selectIndex: 0,
content_code: '',
}));
... ...
... ... @@ -15,7 +15,7 @@ const {
HOME_FAVORITE_REQUEST,
HOME_FAVORITE_SUCCESS,
HOME_FAVORITE_FAILURE,
HOME_KIDS_FAVORITE_REQUEST,
HOME_KIDS_FAVORITE_SUCCESS,
HOME_KIDS_FAVORITE_FAILURE,
... ... @@ -24,6 +24,8 @@ const {
HOME_LIFESTYLE_FAVORITE_SUCCESS,
HOME_LIFESTYLE_FAVORITE_FAILURE,
HOME_LIFESTYLE_FAVORITE_SET_INDEX,
HOME_SHOP_INFO_REQUEST,
HOME_SHOP_INFO_SUCCESS,
HOME_SHOP_INFO_FAILURE,
... ... @@ -65,11 +67,13 @@ export default function homeReducer(state=initialState, action) {
*** 猜你喜欢列表
*****************************/
case HOME_FAVORITE_REQUEST:
case HOME_KIDS_FAVORITE_REQUEST:
case HOME_LIFESTYLE_FAVORITE_REQUEST:{
case HOME_KIDS_FAVORITE_REQUEST:{
let channelStr = action.payload;
return state.setIn([channelStr, 'favorite', 'isFetching'], true);
}
case HOME_LIFESTYLE_FAVORITE_REQUEST:{
return state.setIn(['lifeStyle', 'isListFetching'], true);
}
case HOME_FAVORITE_SUCCESS:
case HOME_KIDS_FAVORITE_SUCCESS:{
let {channelStr, json} = action.payload;
... ... @@ -87,22 +91,24 @@ export default function homeReducer(state=initialState, action) {
.setIn([channelStr, 'favorite', 'error'], error);
}
case HOME_LIFESTYLE_FAVORITE_SUCCESS:{
let {channelStr, json} = action.payload;
return state.setIn([channelStr, 'hotList'], Immutable.fromJS(json.hotList))
.setIn([channelStr, 'newList'], Immutable.fromJS(json.newList))
.setIn([channelStr, 'isFetching'], false)
.setIn([channelStr, 'isFirstLoad'], false)
.setIn([channelStr, 'isListFetching'], false)
.setIn([channelStr, 'endReached'], true);
}
case HOME_LIFESTYLE_FAVORITE_FAILURE:{
let {channelStr, error} = action.payload;
return state.setIn([channelStr, 'isFetching'], false)
.setIn([channelStr, 'listError'], error);
}
case HOME_LIFESTYLE_FAVORITE_SET_INDEX:{
return state.setIn(['lifeStyle', 'selectIndex'], action.payload);
}
/****************************
*** 底部banner
... ... @@ -129,7 +135,7 @@ export default function homeReducer(state=initialState, action) {
let channelStr = action.payload;
return state.setIn([channelStr, 'shop', 'isFetching'], true);
}
case HOME_SHOP_INFO_SUCCESS:{
let {channelStr, json} = action.payload;
return state.setIn([channelStr, 'shop', 'isFetching'], false)
... ... @@ -150,7 +156,7 @@ export default function homeReducer(state=initialState, action) {
.setIn([channelStr, 'cached', 'md5'], data.md5)
.setIn([channelStr, 'cached', 'content_code'], data.content_code);
}
case HOME_FLOOR_DATA_HAS_NOT_CHANGE:{
let channelStr = action.payload;
return state.setIn([channelStr, 'isFetching'], false);
... ...
'use strict';
function homeDataParse(data, channel) {
let {list, cached, isFetching, isFirstLoad, endReached, favorite, bottomBanner, hotList, newList, selectIndex} = data;
let floorList = list.size > 0 ? list.toArray() : cached.get('list').toArray();
let dataSource = {};
if (channel == '4') {
let favlist = selectIndex == 0 ? newList : hotList;
if (endReached) {
dataSource = {
floor: floorList,
lifeStyleFav:favlist.toArray(),
footer: ['1']
}
}else {
dataSource = {
floor: floorList,
}
}
} else {
let favoriteList = favorite.get('list');
let bottomBannerList = bottomBanner.get('list');
if (favoriteList.size == 0) {
dataSource = {
floor: floorList,
}
}else {
if (favoriteList.size > 0 && endReached) {
dataSource = {
floor: floorList,
favoriteHeader: ['1'],
favorite: favoriteList.toArray(),
bottomBanner: [bottomBannerList],
footer: ['1']
}
if (channel == 3) {
dataSource = {
floor: floorList,
favoriteHeader: ['1'],
favorite: favoriteList.toArray(),
footer: ['1']
}
}
}else {
dataSource = {
floor: floorList,
favoriteHeader: ['1'],
favorite: favoriteList.toArray()
}
}
}
}
return dataSource;
}
function channelCacheKey(channelKey) {
return 'YH_RNCacheTypeHomeChannel' + channelKey;
}
... ... @@ -75,6 +129,7 @@ function parseShopInfo(json) {
}
module.exports = {
homeDataParse,
channelCacheKey,
parseHomeFloor,
parseBoyGirlFavorite,
... ...