Expo SDK 29 FlatList onRefresh未调用

时间:2018-09-21 14:31:08

标签: react-native react-redux expo

使用Expo SDK 29来响应本机应用程序。

我想使用平面清单组件。这构成了SafeAreaView组件的整体。我指出这一点是因为滚动视图内部存在很多与平面列表有关的问题,而并非如此。

平面列表显示作业列表。

我在redux状态中添加了一个jobLoading布尔值,以管理列表何时应显示为刷新状态,并可以在触发获取数据的操作和成功操作时确认按预期进行切换。

当我将道具添加到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 :(得分:0)

我遇到了完全相同的问题,并且正在使用expo SDK30。但是我的情况有些不同。每次我拉动时都会调用onRefresh函数,但是如果我向下滚动列表并快速向上滚动,则会显示加载指示器,但是不会调用我的onRefresh函数。

我的刷新器设置在我的reducer上,并且我的onRefresh函数调度一个操作,该操作获取数据并设置刷新的正确与否。

这是我的代码:

    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道具,以防止我的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}
 />
}