当状态/道具改变时,反应原生动画部分列表跳到顶部

Posted

技术标签:

【中文标题】当状态/道具改变时,反应原生动画部分列表跳到顶部【英文标题】:React native animated section list jumps to top when state/props change 【发布时间】:2019-10-13 11:59:00 【问题描述】:

我正在一个带有部分列表组件的本机应用程序中构建一个视图,它上面还有一个标题,它将显示有关列表的聚合数据。滚动时,标题视图应该随着动画缩小。我的所有动画都可以正常工作,但是在使用 onEndreached 属性添加无限滚动时会出现问题。当添加新数据或状态/道具发生变化时,它会跳到列表的顶部。

为了使 SectionList 具有动画效果,我使用 Animated.createAnimatedComponent 对其进行了包装,以创建一个 <AnimatedSectionList /> 组件。当它被 Animated 包裹时,问题就出现了。

在下面链接的 gif 中,您可以看到当我向下滚动时它会跳到列表的顶部。这是状态发生变化并且我们开始获取更多数据的时候。 https://monosnap.com/file/2aH5iPF2XcygEz381bpHW9QGPGHA2Z

我尝试使用getItemLayout 来计算列表大小,希望是因为我读到当 react 不知道列表的高度时,它可能会很跳跃。

我还尝试在使用scrollTo 加载新数据后滚动到某个部分,但这也不起作用。我使用 componentDidUpdate 生命周期方法执行此操作,但是当新数据进入时,componentDidUpdate 并没有被一致地调用。

这是我的代码。


const DataItem = [
   name: "test name", value: "testvalue" ,
   name: "test name", value: "testvalue" ,
   name: "test name", value: "testvalue" ,
   name: "test name", value: "testvalue" ,
   name: "test name", value: "testvalue" 
];

const initialSections = [
   title: "MY DETAILS", data: DataItem ,
   title: "MY COMMUNITY", data: DataItem ,
   title: "MY FAMILY", data: DataItem 
];

const styles = 
  item: 
    flex: 1,
    height: 50,
    marginTop: 1,
    backgroundColor: "#dddddd"
  ,
  sectionHeader: 
    flex: 1,
    height: 20,
    marginTop: 1,
    backgroundColor: "#00ff00"
  
;



class Edit extends Component 
  constructor(props) 
    super(props);

    this.state = 
      scrollEnabled: true,
      scrollY: new Animated.Value(0),
      sections: initialSections,
      refreshing: false
    ;


  _renderSectionHeader(section) 
    return (
      <View style=styles.sectionHeader>
        <Text> section.title </Text>
      </View>
    );
  

  _renderItem(item) 
    return (
      <View style=styles.item>
        <Text>item.name</Text>
      </View>
    );
  


  handleStateButton() 
    this.setState( refreshing: true );
  

  fetchMoreData() 
    this.setState( refreshing: true );

    const newData = [...this.state.sections, ...initialSections];

    setTimeout(
      function() 
        this.setState( sections: newData, refreshing: false );       .bind(this),
      2000
    );
  

  render() 
    const backgroundScrollY = this.state.scrollY.interpolate(
      inputRange: [0, 224],
      outputRange: [0, -50],
      extrapolate: "clamp"
    );

    const backgroundScrollHeight = this.state.scrollY.interpolate(
      inputRange: [0, 224],
      outputRange: [1, 0.75],
      extrapolate: "clamp"
    );

    const listScrollY = this.state.scrollY.interpolate(
      inputRange: [0, 224],
      outputRange: [0, -10],
      extrapolate: "clamp"
    );

    const infoOpacity = this.state.scrollY.interpolate(
      inputRange: [0, 0.5, 150],
      outputRange: [1, 1, 0],
      extrapolate: "clamp"
    );

    const AnimatedSectionList = Animated.createAnimatedComponent(SectionList);

    return (
      <View
        style=
          flex: 1,
          //   alignItems: "flex-start",
          flexDirection: "column"
        
      >
        <Animated.View
          style=[
            
              position: "relative",
              // flex: 1,
              // alignSelf: "flex-start",
              top: 0,
              minHeight: 200,
              height: 300,
              backgroundColor: "#ddee99",
              border: "1px solid #0000FF",
              justifyContent: "center",
              alignItems: "center"
            ,
             transform: [ scaleY: backgroundScrollHeight ] 
          ]
        >
          <Animated.Image
            source=
              uri:
                "https://images.unsplash.com/photo-1558901591-3a5f333830dd?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"
            
            style=[
               position: "absolute", backgroundColor: "#cccccc" ,
               transform: [ translateY: backgroundScrollY ] 
            ]
            blurRadius=1.5
          />

          <Text>this.state.refreshing && `Fetching data`</Text>

          <Button onPress=this.fetchMoreData title="Get More Data" />
          <Button onPress=this.handleStateButton title="Changing State" />
        </Animated.View>

        <AnimatedSectionList
          ref=ref => (this.sectionListRef = ref)
          bounces=false
          scrollEnabled=this.state.scrollEnabled
          style=[
             position: "relative" ,
             transform: [ translateY: listScrollY ] 
          ]
          onScroll=Animated.event(
            [ nativeEvent:  contentOffset:  y: this.state.scrollY   ],
             listener: this._onScroll.bind(this) 
          )
          sections=this.state.sections
          renderSectionHeader=( section ) =>
            this._renderSectionHeader(section)
          
          ListHeaderComponent=() => (
            <View
              style=
                flex: 1,
                flexDirection: "row",
                alignItems: "center",
                height: 40,
                backgroundColor: "#ff00ff"
              
            >
              <Text>List Header</Text>
            </View>
          )
          ListFooterComponent=() => (
            <View
              style=
                flex: 1,
                flexDirection: "row",
                alignItems: "center",
                height: 80,
                backgroundColor: "#FF0"
              
            >
              <Text>List Footer</Text>
            </View>
          )
          getItemLayout=this.getItemLayout
          renderItem=( item ) => this._renderItem(item)
          keyExtractor=(item, index) => index
          stickySectionHeadersEnabled=true
          onEndReachedThreshold=0.75
          onEndReached=d => 
            this.fetchMoreData();
          
        />
      </View>
    );
  



我希望当 state 或 props 发生变化时列表会保持在当前滚动的位置,但是它会跳到顶部,从而破坏了无限滚动的目的。

对于解决此问题的最佳方法的任何想法,我们将不胜感激。

【问题讨论】:

【参考方案1】:

我把

const AnimatedSectionList = Animated.createAnimatedComponent(SectionList);

退出班级,不再跳到榜首

【讨论】:

以上是关于当状态/道具改变时,反应原生动画部分列表跳到顶部的主要内容,如果未能解决你的问题,请参考以下文章

如何隐藏和显示加载微调器 - 活动指示器反应原生,管理道具和状态

反应孩子正在通过道具改变父母状态......我不清楚原因

在不改变状态、道具或父级的情况下反应子级渲染

即使道具没有改变,为啥还要对重新渲染组件做出反应?

更新道具时反应本机组件不透明度不更新

反应原生返回 null 状态