How can I sync two flatList scroll position in react native

笑着哭i 提交于 2019-12-11 08:39:34

问题


As you can see in the picture above, there is a vertical list of two columns. I have developed two flatLists because I can not style photos with different height on one line with the flatList column option.

I want two flatLists to have the same scroll position.

I wrapped two FlatList component with to synchronize scrolling. But there is a problem here. The scrollView ignores the infinity scroll and calls the pagination objects all at once. There is a performance problem.

How can I solve this problem?

here is my component code

import React from 'react';
import { View, Platfrom, Text, StyleSheet, AsyncStorage, TouchableOpacity, Image, FlatList, Button, Dimensions, ScrollView, ListView } from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import { NavigationActions } from 'react-navigation';
import { connect } from 'react-redux';
import moment from 'moment';

import * as settings from '../../config/settings';
import Menu from '../menu';

import headerStyles from '../../styles/common/header';
import textStyles from '../../styles/common/text';
import containerStyles from '../../styles/common/container';
import imageStyles from '../../styles/common/image';
import boxStyles from '../../styles/common/box';
import objectStyles from '../../styles/common/object';
import commonStyles from '../../styles/common/common';
import colorStyles from '../../styles/common/color';


const window = Dimensions.get('window');

const styles = StyleSheet.create({
    listView: {
        paddingTop: 20,
        backgroundColor: '#FFFFFF',
    },
    fullScreen: {
        flex: 1,
        marginBottom: 50,
    },
    floatView: {
        position: 'absolute',
        width: '90%',
        marginLeft: '5%',
        height: 100,
        bottom: -50,
    },
});

const phoneWidth = Dimensions.get('window').width

class PurchaseListScreen extends React.Component {
    static navigationOptions = ({ navigation }) => {
        const { params = {} } = navigation.state
        return {
            title: '중고 명품 구매',
            headerStyle: headerStyles.header,
            headerTitleStyle: headerStyles.headerTitle,
            headerRight: <Icon name="bars" size={30} color="#333" onPress={() => { params.showModal() }} style={{ padding: 10 }} />,
        }
    }

    constructor(props) {
        super(props);
        this.state = {
            user_token: '',
            refreshing: false,
            isModalVisible: false,
            leftColumneData: [],
            rightColumneData: [],
            leftNextKey: '',
            rightNextKey: '',
        };
        this.hideModal = this.hideModal.bind(this);
    }

    componentDidMount() {
        this.props.navigation.setParams({ showModal: this.showModal });
        this.purchaseListService();
    }

    showModal = () => this.setState({ isModalVisible: true })

    hideModal = () => this.setState({ isModalVisible: false })

    navigate1 = (item) => {
        console.log('click navigate1');
        const navigate1 = NavigationActions.navigate({
            routeName: "home",
        });
        this.props.navigation.dispatch(navigate1);
    };

    purchaseListService = async () => {
        if (this.props.isLoggedIn) {
            let user_info = await AsyncStorage.getItem('user_info');
            get_user_token = JSON.parse(user_info).key;
            this.setState({ user_token: get_user_token });

            const api_uri1 = settings.base_uri + 'purchase-product/odd/'
            const request1 = {
                method: 'GET',
                headers: {
                    'Authorization': 'Token ' + get_user_token,
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                }
            }

            const api_uri2 = settings.base_uri + 'purchase-product/even/'
            const request2 = {
                method: 'GET',
                headers: {
                    'Authorization': 'Token ' + get_user_token,
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                }
            }

            fetch(api_uri1, request1)
                .then(res => res.json())
                .then(res => {
                    this.setState({
                        leftColumneData: [...res.results],
                        leftNextKey: res.next
                    })
                })
                .catch((error) => {
                    console.error(error);
                })

            fetch(api_uri2, request2)
                .then(res => res.json())
                .then(res => {
                    this.setState({
                        rightColumneData: [...res.results],
                        rightNextKey: res.next,
                    })
                })
                .catch((error) => {
                    console.error(error);
                })

        } else {
            const api_uri1 = settings.base_uri + 'purchase-product/odd/'
            const request1 = {
                method: 'GET',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                }
            }

            const api_uri2 = settings.base_uri + 'purchase-product/even/'
            const request2 = {
                method: 'GET',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                }
            }

            fetch(api_uri1, request1)
                .then(res => res.json())
                .then(res => {
                    this.setState({
                        leftColumneData: [...res.results],
                        leftNextKey: res.next,
                    })
                })
                .catch((error) => {
                    console.error(error);
                })

            fetch(api_uri2, request2)
                .then(res => res.json())
                .then(res => {
                    this.setState({
                        rightColumneData: [...res.results],
                        rightNextKey: res.next,
                    })
                })
                .catch((error) => {
                    console.error(error);
                })
        }
    }

    onEndReachedService = () => {
        console.log('run onEndReachedService');
        if (this.props.isLoggedIn && this.state.leftNextKey) {
            const api_uri1 = this.state.leftNextKey
            const request1 = {
                method: 'GET',
                headers: {
                    'Authorization': 'Token ' + this.state.user_token,
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                }
            }

            const api_uri2 = this.state.rightNextKey
            const request2 = {
                method: 'GET',
                headers: {
                    'Authorization': 'Token ' + this.state.user_token,
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                }
            }

            fetch(api_uri1, request1)
                .then(res => res.json())
                .then(res => {
                    this.setState({
                        leftColumneData: [...this.state.leftColumneData, ...res.results],
                        leftNextKey: res.next
                    })
                })
                .catch((error) => {
                    console.error(error);
                })

            fetch(api_uri2, request2)
                .then(res => res.json())
                .then(res => {
                    this.setState({
                        rightColumneData: [...this.state.rightColumneData, ...res.results],
                        rightNextKey: res.next,
                    })
                })
                .catch((error) => {
                    console.error(error);
                })

        } else if (!this.props.isLoggedIn && this.state.leftNextKey){
            const api_uri1 = this.state.leftNextKey
            const request1 = {
                method: 'GET',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                }
            }

            const api_uri2 = this.state.rightNextKey
            const request2 = {
                method: 'GET',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                }
            }

            fetch(api_uri1, request1)
                .then(res => res.json())
                .then(res => {
                    console.log('update res1', res);
                    this.setState({
                        leftColumneData: [...this.state.leftColumneData, ...res.results],
                        leftNextKey: res.next,
                    })

                })
                .catch((error) => {
                    console.error(error);
                })

            fetch(api_uri2, request2)
                .then(res => res.json())
                .then(res => {
                    console.log('update res2', res);
                    this.setState({
                        rightColumneData: [...this.state.rightColumneData, ...res.results],
                        rightNextKey: res.next,
                    })
                })
                .catch((error) => {
                    console.error(error);
                })
        }
    }

    likeService = async (pk, column) => {
        let user_info = await AsyncStorage.getItem('user_info');
        user_token = JSON.parse(user_info).key;
        const api_uri = settings.base_uri + 'purchase-product/' + pk + '/like/'

        var request = {
            method: 'POST',
            headers: {
                'Authorization': 'Token ' + user_token,
                'Accept': 'application/json',
                'Content-Type': 'application/json',
            }
        };

        fetch(api_uri, request)
            .then(res => {
                if(column=='left'){
                    var items = this.state.leftColumneData
                    for (i=0; i<items.length; i++) {
                        let item = items[i]
                        if (item.id==pk) {
                            item.is_liked = !item.is_liked
                            items[i] = item;
                            this.setState({ leftColumneData: items })
                        }
                    }
                } else {
                    var items = this.state.rightColumneData
                    for (i = 0; i < items.length; i++) {
                        let item = items[i]
                        if (item.id == pk) {
                            item.is_liked = !item.is_liked
                            items[i] = item;
                            this.setState({ rightColumneData: items })
                        }
                    }
                }
            })
            .catch((error) => {
                console.error(error);
            });
    }

    renderLabel = (text) => {
        if (text) {
            return (
                <View style={{ backgroundColor: 'red', paddingVertical: 2, marginLeft: 3, marginTop: 5, marginBottom: 8, paddingHorizontal: 4 }}>
                    <Text style={{ color: 'white', fontSize: 9, fontWeight: '400' }}>{text}</Text>
                </View>
            )
        } else {
            return (
                <View style={{ paddingVertical: 2, marginTop: 5, marginBottom: 8, }}>
                </View>
            )
        }
    }

    renderList = (item, column) => {
        return(
            <View>
                <View style={{ 
                    flex: 1, 
                    borderColor: 'rgb(136, 136, 136)', 
                    borderWidth: 1, 
                    marginLeft: 15, 
                    marginTop: 15,
                    backgroundColor: 'white',
                    }}>
                    <TouchableOpacity onPress={()=>{}}>
                    {item.is_vertical?
                        <Image
                            source={{ uri: item.first_thumbnail }}
                            style={{ flex:1, height: 210 }}/>
                        :
                        <Image
                            source={{ uri: item.first_thumbnail }}
                            style={{ flex: 1, height: 130 }} />
                    }
                    </TouchableOpacity>
                    <View style={{ flex: 1 }}>
                        <View style={{ flexDirection: 'row' }}>
                            <TouchableOpacity style={{ flex: 4 }}>
                                <Text style={{
                                    fontSize: 14,
                                    fontWeight: '600',
                                    color: 'rgb(35, 31, 32)',
                                    marginTop: 10,
                                    marginLeft: 8
                                }}>{item.name}</Text>
                                <Text style={{
                                    fontSize: 12,
                                    fontWeight: '500',
                                    color: 'rgb(35, 31, 32)',
                                    marginLeft: 8,
                                    marginTop: 8
                                }}>{item.partner.biz_name}</Text>
                                <View style={{ flexDirection: 'row', marginLeft: 6 }}>
                                    {this.renderLabel(item.product_type_str)}
                                    {this.renderLabel(item.city.name)}
                                </View>
                            </TouchableOpacity>

                            <View
                                style={{ flex: 1, marginTop: 10, marginRight: 2, alignItems: 'center' }}>
                                {this.props.isLoggedIn ? 
                                    <View>
                                        {item.is_liked ?
                                            <Icon
                                                name="heart" size={17} color="red"
                                                onPress={() => {
                                                    this.likeService(item.id, column);
                                                }} />
                                            : <Icon name="heart-o" size={17} color="red"
                                                onPress={() => {
                                                    this.likeService(item.id, column);
                                                }} />
                                        }
                                    </View> : 
                                    <View>
                                        <Icon name="heart-o" size={17} color="red"
                                            onPress={() => {
                                                console.log('press heart', column);
                                            }} />
                                    </View>}
                            </View>

                        </View>
                        <View style={[ colorStyles.greenBackground,
                            {
                                flex: 1,
                                borderTopWidth: 1,
                                borderColor: 'rgb(136, 136, 136)',
                                padding: 5,
                                paddingRight: 10,
                            }]}>
                            <Text style={{ 
                                textAlign: 'right',
                                fontSize: 14,
                                fontWeight: '500',
                                color: 'rgb(35, 31, 32)',
                            }}>
                                {(item.price).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}원 {item.id}
                            </Text>
                        </View>
                    </View>
                </View>
            </View>
        )
    }

    render() {   
        return (
            <View style={{ flex: 1 }}>
                <Menu hideModal={this.hideModal.bind(this)} isVisible={this.state.isModalVisible} navigation={this.props.navigation} />
                <View style={{ flexDirection: 'row' }}>
                    <FlatList
                        style={{ flex: 1 }}
                        showsVerticalScrollIndicator={false}
                        initialNumToRender={20}
                        onEndReachedThreshold={1}
                        onEndReached={this.onEndReachedService}
                        refreshing={this.state.refreshing}
                        onRefresh={this.purchaseListService.bind(this)}
                        data={this.state.leftColumneData}
                        renderItem={({ item }) => this.renderList(item, column='left')}
                        keyExtractor={(item) => item.id}
                    />
                    <FlatList
                        style={{ flex: 1, paddingRight: 15  }}
                        showsVerticalScrollIndicator={false}
                        refreshing={this.state.refreshing}
                        onRefresh={this.purchaseListService.bind(this)}
                        data={this.state.rightColumneData}
                        renderItem={({ item }) => this.renderList(item, column='right')}
                        keyExtractor={(item) => item.id}
                    />
                </View>
            </View>
        )
    }
}


const mapStateToProps = state => ({
    isLoggedIn: state.loginReducer.isLoggedIn
})

const PurchaseList = connect(mapStateToProps, null)(PurchaseListScreen);

export default PurchaseList;

来源:https://stackoverflow.com/questions/48057527/how-can-i-sync-two-flatlist-scroll-position-in-react-native

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!