Skip to content

Commit

Permalink
refactor(tab-set): component structure separation
Browse files Browse the repository at this point in the history
  • Loading branch information
Artur Yorsh committed Oct 23, 2018
1 parent 9e402b0 commit 90000c2
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 175 deletions.
5 changes: 2 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ export { RkModalImg } from './src/components/image/rkModalImg';
export { RkGallery } from './src/components/gallery/rkGallery';
export { RkGalleryImage } from './src/components/gallery/rkGalleryImage';
export { RkCalendar } from './src/components/calendar/rkCalendar.component';
export { RkTabView } from './src/components/tab/rkTabView';
export { RkTabSet } from './src/components/tabset/rkTabSet.component';
export { RkTabSetItem } from './src/components/tabset/rkTabSetItem.component';
export { RkTabView } from './src/components/tabset/rkTabView.component';
export { RkTab } from './src/components/tabset/rkTab.component';
export { RkCard } from './src/components/card/rkCard';
export { RkAvoidKeyboard } from './src/components/avoidKeyboard/rkAvoidKeyboard';
export { RkComponent } from './src/components/rkComponent';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@ import {
} from 'react-native';
import { RkStyleSheet } from '../../styles/styleSheet';

export class RkTabSetItem extends React.PureComponent {
export class RkTab extends React.PureComponent {
static propTypes = {
title: PropTypes.string,
isSelected: PropTypes.bool,
isLazyLoad: PropTypes.bool,
};
static defaultProps = {
title: '',
isSelected: false,
isLazyLoad: true,
};

state = {
isSelected: RkTabSetItem.defaultProps.isSelected,
isSelected: RkTab.defaultProps.isSelected,
};

static getDerivedStateFromProps(props) {
Expand Down
47 changes: 47 additions & 0 deletions src/components/tabset/rkTabBar.component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
View,
TouchableOpacity,
StyleSheet,
} from 'react-native';
import { RkTab } from './rkTab.component';

export class RkTabBar extends React.Component {
static propTypes = {
children: PropTypes.arrayOf(PropTypes.instanceOf(RkTab)).isRequired,
selectedIndex: PropTypes.number,
onSelect: PropTypes.func,
};
static defaultProps = {
selectedIndex: 0,
onSelect: (() => null),
};

shouldComponentUpdate(nextProps) {
return this.props.selectedIndex !== nextProps.selectedIndex;
}

onChildPress = (index) => {
this.props.onSelect(index);
};

renderChild = (item, index) => (
<TouchableOpacity key={index.toString()} onPress={() => this.onChildPress(index)}>
{ React.cloneElement(item, { isSelected: this.props.selectedIndex === index }) }
</TouchableOpacity>
);

renderChildComponents = () => this.props.children.map(this.renderChild);

render = () => (
<View style={styles.container}>{this.renderChildComponents()}</View>
);
}

const styles = StyleSheet.create({
container: {
flexDirection: 'row',
justifyContent: 'space-between',
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { RkStyleSheet } from '../../styles/styleSheet';

const defaultAnimationDuration = 200;

export class RkTabSetIndicator extends React.PureComponent {
export class RkTabBarIndicator extends React.PureComponent {
static propTypes = {
itemCount: PropTypes.number.isRequired,
contentWidth: PropTypes.number.isRequired,
Expand Down
137 changes: 137 additions & 0 deletions src/components/tabset/rkTabPager.component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
View,
FlatList,
} from 'react-native';

export class RkTabPager extends React.Component {
static propTypes = {
children: PropTypes.arrayOf(PropTypes.node).isRequired,
selectedIndex: PropTypes.number,
onSelect: PropTypes.func,
shouldUseLazyLoad: PropTypes.func,
};
static defaultProps = {
selectedIndex: 0,
onSelect: (() => null),
shouldUseLazyLoad: (() => true),
};

state = {
items: [],
componentWidth: -1,
};

containerRef = undefined;
lazyLoadItemMap = new Map();

static getDerivedStateFromProps(props) {
return {
items: props.children,
};
}

constructor(props) {
super(props);
props.children.forEach((item, index) => {
const isDerivedSelection = props.selectedIndex === index;
const isShouldUseLazyLoad = isDerivedSelection ? false : props.shouldUseLazyLoad(index);
this.setShouldUseLazyLoad(index, isShouldUseLazyLoad);
});
}

onLayout = (event) => {
this.setState({
componentWidth: event.nativeEvent.layout.width,
});
};

onContainerScroll = (event) => {
const selectedIndex = Math.round(event.nativeEvent.contentOffset.x / this.state.componentWidth);
const isIndexInBounds = selectedIndex >= 0 && selectedIndex <= this.props.children.length;

// TODO: scroll indicator on container gesture scroll
//
// const contentIndicatorOffset = event.nativeEvent.contentOffset.x / this.props.children.length;
// this.contentIndicatorRef.scrollToOffset({ offset: contentIndicatorOffset });

if (isIndexInBounds && selectedIndex !== this.props.selectedIndex) {
this.onItemChange(selectedIndex);
}
};

onItemChange = (index) => {
this.props.onSelect(index);
};

/**
* @param params - object: { index: number, animated: boolean }
*/
scrollToIndex = (params) => {
this.containerRef.scrollToIndex(params);
};

/**
* @param params - object: { offset: number, animated: boolean }
*/
scrollToOffset = (params) => {
this.containerRef.scrollToOffset(params);
};

setContainerRef = (ref) => {
this.containerRef = ref;
};

getItemKey = (item, index) => index.toString();

getItemLayout = (item, index) => ({
length: this.state.componentWidth,
offset: this.state.componentWidth * index,
index,
});

isShouldUseLazyLoad(index) {
return this.lazyLoadItemMap.get(index);
}

setShouldUseLazyLoad(index, value) {
this.lazyLoadItemMap.set(index, value);
}

renderItem = ({ item, index }) => {
const isItemSelected = index === this.props.selectedIndex;
const isShouldUseLazyLoad = this.isShouldUseLazyLoad(index);
const isShouldLoadContentView = isItemSelected || !isShouldUseLazyLoad;
const contentView = isShouldLoadContentView ? item : null;

this.setShouldUseLazyLoad(index, !isShouldLoadContentView);

return (
<View style={{ width: this.state.componentWidth }}>{contentView}</View>
);
};

renderPlaceholder = () => (
<View onLayout={this.onLayout} />
);

renderView = () => (
<FlatList
ref={this.setContainerRef}
horizontal={true}
pagingEnabled={true}
removeClippedSubviews={true}
initialScrollIndex={this.props.selectedIndex}
data={this.state.items}
onScroll={this.onContainerScroll}
renderItem={this.renderItem}
getItemLayout={this.getItemLayout}
keyExtractor={this.getItemKey}
/>
);

render() {
return this.state.componentWidth < 0 ? this.renderPlaceholder() : this.renderView();
}
}
169 changes: 0 additions & 169 deletions src/components/tabset/rkTabSet.component.js

This file was deleted.

Loading

0 comments on commit 90000c2

Please sign in to comment.