首页 文章

Expo SDK 29 FlatList onRefresh不调用

提问于
浏览
0

使用Expo SDK 29作为反应本机应用程序 .

我想使用一个平面列表组件 . 这构成了SafeAreaView组件的整体 . 我提出这一点,因为滚动视图中的平面列表存在许多问题,而这不是 .

单位列表显示了一份工作清单 .

我已经将一个jobLoading boolean添加到redux状态,以管理列表应该显示为刷新的时间,并且可以确认在触发获取数据和成功的操作时,这会按预期切换 .

当我将道具添加到onRefresh的平面列表中时,刷新组件似乎通过在UI中显示活动指示器但不启动onRefresh函数来工作 . 我尝试过多种方式实现调用,但没有任何反应 . 结果是活动指示器显示自己并且永远不会消失 .

由于它是Expo SDK 29,因此React Native版本为0.55.4

任何人都有任何尝试的想法 . 我花了几个小时看着尝试各种各样的事情,但欢迎提出建议 .

提前致谢 .

编辑:添加代码供参考 . 用于刷新的Reducer在调度fetchJobs()时设置为true,在收到成功或错误时设置为false . onRefresh的控制台日志永远不会触发 .

import * as React from 'react'
import * as actions from '../../redux/actions'
import { ActivityIndicator, FlatList, KeyboardAvoidingView, Dimensions, SafeAreaView, StyleSheet, View } from 'react-native'
import { ApplicationState, JobState, Job } from '../../redux'
import { Button, Form, Input, Item, Text, Icon } from 'native-base'
import { JobListItem } from './jobListItem'
import { StateHandlerMap, compose, lifecycle, withPropsOnChange, withStateHandlers } from 'recompose'
import { connect } from 'react-redux'

interface ReduxStateProps {
    jobs: JobState
    refreshing: boolean
    screenOrientation: string
}

interface ReduxDispatchProps {
    fetchJobs: (param?: string) => any
}

export interface DataItem {
    key: string
    data: Job
}

interface ListProps {
    jobList: DataItem[]
}

interface SearchStateProps {
    timer: number | undefined
    searchString: string
}

interface SearchHandlerProps extends StateHandlerMap<SearchStateProps> {
    updateSearch: (searchString: string) => any
    setTimer: (timer: number | undefined) => any
}

type OuterProps = {}
type InnerProps = OuterProps & ReduxStateProps & ReduxDispatchProps & ListProps & SearchStateProps & SearchHandlerProps

const enhance = compose<InnerProps, OuterProps>(
    connect<ReduxStateProps, ReduxDispatchProps, OuterProps, ApplicationState>(
        state => ({
            jobs: state.job,
            refreshing: state.jobLoading,
            screenOrientation: state.screenOrientation
        }),
        dispatch => ({
            fetchJobs: (param?: string) => dispatch(actions.jobs.request({ param }))
        })
    ),
    withPropsOnChange<ListProps, OuterProps & ReduxStateProps & ReduxDispatchProps>(
        ['jobs', 'screenOrientation'],
        props => ({
            jobList: props.jobs && Object.keys(props.jobs).map(job => ({ key: job, data: props.jobs[Number(job)] }))
        })
    ),
    withStateHandlers<SearchStateProps, SearchHandlerProps, OuterProps>(
        {
            timer: undefined,
            searchString: ''
        },
        {
            updateSearch: state => (searchString: string) => ({ searchString }),
            setTimer: state => (timer: number | undefined) => ({ timer })
        }
    ),
    lifecycle<InnerProps, {}>({
        componentDidMount() {
            this.props.fetchJobs()
        }
    })
)

export const JobList = enhance(({ fetchJobs, jobList, refreshing, screenOrientation, searchString, setTimer, timer, updateSearch }) => {

    const onSearchChange = (search: string) => {
        clearTimeout(timer)

        updateSearch(search)

        const timing = setTimeout(() => {
            fetchJobs(search)
        }, 500)

        setTimer(timing)
    }
const onRefresh = () => {
    console.log('requesting refresh')
    fetchJobs()
}

return (
    <SafeAreaView style={{ flex: 1}}>
        <KeyboardAvoidingView style={{ flexDirection: 'row', justifyContent: 'space-evenly', paddingTop: 3, paddingRight: 3 }}>
            <Form style={{ flex: 1, paddingLeft: 10, paddingRight: 10 }}>
                <Item>
                    <Input
                        value={searchString}
                        onChangeText={(text: string) => onSearchChange(text)}
                        placeholder='Search' 
                    />
                </Item>
            </Form>
            <Button onPress={() => {fetchJobs(); updateSearch('')}}>
                <Icon name='refresh' />
            </Button>
        </KeyboardAvoidingView>

        {refreshing && 
            <View style={styles.refreshContainer}>
                <Text style={{ paddingBottom: 10 }}>Fetching Data</Text>
                <ActivityIndicator />
            </View>
        }
        <FlatList
            keyExtractor={item => item.key} 
            data={jobList}
            renderItem={({ item }) => 
                <JobListItem 
                    screenOrientation={screenOrientation}
                    item={item}
                />
            }
            onRefresh={onRefresh}
            refreshing={refreshing}
        />
    </SafeAreaView>
)
})

const styles = StyleSheet.create({
    refreshContainer: {
        height: 60,
        flex: 1,
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center'
    }
})

1 回答

  • 0

    我有完全相同的问题,我正在使用expo SDK 30.但我的情况有点不同 . 每次拉动时都会调用onRefresh函数,但是如果我向下滚动列表并快速向上滚动,加载指示器会显示,但我的onRefresh函数不会被调用 .

    我的刷新道具是在我的reducer上设置的,我的onRefresh函数调度一个动作来获取数据并设置刷新的true和false .

    这是我的代码:

    class NoticiasScreen extends Component {
      static navigationOptions = {
        header: <Header
                  title='Notícias Alego'
                  leftComponent={<Image source={require('../../../assets/images/play_grande.png')} style={imageStyle} resizeMode='contain'/>}
                />
      }
    
      constructor(props) {
        super(props);
    
        this.renderItem = this.renderItem.bind(this);
        this.keyExtractor = this.keyExtractor.bind(this);
        this.renderContent = this.renderContent.bind(this);
        this.navigateToNoticias = this.navigateToNoticias.bind(this);
        this.carregarMaisNoticias = this.carregarMaisNoticias.bind(this);
        this.onRefresh = this.onRefresh.bind(this);
      }
    
      componentDidMount() {
        this.props.carregarNoticias(this.props.pagina);
      }
    
      renderItem({item}) {
        return (
          <NoticiaListItem noticia={item} abrirNoticia={this.navigateToNoticias} />
        );
      }
    
      keyExtractor(item) {
        return item.id.toString();
      }
    
      navigateToNoticias(noticia) {
        this.props.navigation.navigate('NoticiasExibir', { id: noticia.id });
      }
    
      onRefresh() {
        console.log('onRfresh');
        this.props.carregarNoticias(1, true);
      }
    
      carregarMaisNoticias() {
        const { carregarNoticias, pagina } = this.props;
        carregarNoticias(pagina + 1);
      }
    
      renderContent() {
        const { noticias, carregandoNoticias, erroNoticias } = this.props;
    
        if(noticias.length === 0 && carregandoNoticias) {
          return (
            <View style={styles.containerCenter}>
              <ActivityIndicator size="large" color={colors.verde}/>
            </View>
          );
        }
    
        if(erroNoticias) {
          return (
            <View style={styles.containerCenter}>
              <Text style={styles.message}>{erroNoticias}</Text>
              <TouchableOpacity hitSlop={hitSlop15}>
                <Text>Recarregar</Text>
              </TouchableOpacity>
            </View>
          )
        }
    
        return (
          [<TextInput
            style={styles.textInput}
            placeholder='Pesquise'
            key='pesquisa'
            underlineColorAndroid='transparent'
          />,
          <FlatList
            data={noticias}
            renderItem={this.renderItem}
            keyExtractor={this.keyExtractor}
            style={styles.list}
            key='lista'
            onRefresh={this.onRefresh}
            refreshing={carregandoNoticias}
            onEndReached={this.carregarMaisNoticias}
            onEndReachedThreshold={0.1}
          />]
        )
      }
    
      render() {
        return (
          <SafeAreaView style={styles.safeArea}>
            <View style={styles.container}>
    
              {this.renderContent()}
            </View>
          </SafeAreaView>
        );
      }
    }
    
    function mapStateToProps(state) {
      return {
        noticias: state.intranet.noticias,
        pagina: state.intranet.pagina,
        erroNoticias: state.intranet.erroNoticias,
        carregandoNoticias: state.intranet.carregandoNoticias
      }
    }
    
    function mapDispatchToProps(dispatch) {
      return {
        carregarNoticias: (pagina, recarregar) => dispatch(ActionCreator.carregarNoticias(pagina, recarregar))
      }
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(NoticiasScreen);
    

    不知道发生了什么 . 任何帮助表示赞赏 .

    编辑:

    我以某种方式解决了它 . 我添加了onMomentScrollBegin prop以防止我的flatList在Render上呈现两次,并解决了这个问题 .

    这是我添加的内容:

    constructor(props) {
        super(props);
    
        ...
    
        this.onRefresh = this.onRefresh.bind(this);
    
    
        this.onMomentumScrollBegin = this.onMomentumScrollBegin.bind(this);
    
        this.onEndReachedCalledDuringMomentum = true; //PUT THIS HERE
      }
    
    
     onRefresh() {
        this.props.carregarNoticias(1, true);
      }
    
      carregarMaisNoticias() {
        if(!this.onEndReachedCalledDuringMomentum){
          const { carregarNoticias, pagina } = this.props;
          carregarNoticias(pagina + 1);
          this.onEndReachedCalledDuringMomentum = true;
        }
      }
    
      onMomentumScrollBegin() {
        this.onEndReachedCalledDuringMomentum = false;
      }
    
    render() {
      <OptimizedFlatList
        data={noticias}
        renderItem={this.renderItem}
        keyExtractor={this.keyExtractor}
        style={styles.list}
        key='lista'
        onRefresh={this.onRefresh}
        refreshing={carregandoNoticias}
        onMomentumScrollBegin={this.onMomentumScrollBegin} //PUT THIS HERE
        onEndReached={this.carregarMaisNoticias}
        onEndReachedThreshold={0.1}
     />
    }
    

相关问题