重新渲染(更新)子组件时正在重新启动的ScrollView位置

时间:2020-05-08 20:54:45

标签: reactjs react-native react-redux scrollview

我遇到了一个问题(在渲染周期中可能忽略了这一点),当更新其子组件的某些组件时,它们保持两个不同的滚动视图的位置。

我有一个类似的视图层次结构:

<ScrollView vertical scrolling ability>
    ...
    <ScrollView horizontal and vertical scrolling ability>
    ...
        <Matrix>
            <Cell updateCellStatusHandler={handler}>
        </Matrix>
    ...
    </ScrollView>
</ScrollView>

因此,内部单元格上的更新正在重置单元格状态更新上的两个滚动,这产生了一种超级怪异的体验,用户必须向下/向左/向右滚动以继续与具有状态的单元格矩阵进行交互我有。

我尝试使用useState保存scrollOffset(x,y),但是如果更改某些单元格,则状态会重置为(0,0),这是我的初始状态。

const [scrollOffset, setScrollOffset] = useState({
    scrollX: 0,
    scrollY: 0,
})

但是没有运气。

<ScrollView
      {...props}
      scrollEventThrottle={16}
      ref={scrollReference}
      // tslint:disable-next-line: jsx-no-lambda
      onScroll={event => {
        setScrollOffset({
          scrollX: event.nativeEvent.contentOffset.x,
          scrollY: event.nativeEvent.contentOffset.y,
        })
      }}
      onScrollEndDrag={event => {
        console.log(event.nativeEvent.contentOffset.y)
        console.log(event.nativeEvent.contentOffset.x)
      }}
    >
      {props.children}
</ScrollView>

解决此问题的一种可能方法是拥有一种机制,允许我在更新之前保存滚动位置。但这会使组件之间的通信复杂化很多,等等。 顺便说一下,单元状态更新是通过Redux处理的。

如果你们中的一些人能对此有所了解,那就太好了。

---- UPDATE 1(添加了面板组件的代码)----

父组件是:

<View style={styles.container}>
      <CustomScrollView enableResetScrollToCoords={false}>
        <Section>
          <WhiteContainer>
            <View style={styles.rateContainer}>
              <DescriptionTextStatus
                statusText={getMessageForRate(availabilityRate)}
                descriptionText={getDescriptionForRate(
                  availabilityRate,
                  isTeacher,
                )}
                icon={getImageForRate(availabilityRate)}
              />
            </View>
          </WhiteContainer>
        </Section>
        {!loggedUserIsTeacher() && <AvailabilityStart />}
        <AvailabilityPanel />
        <AvailabilityStatus />
        <AvailabilityButtonSave />
      </CustomScrollView>
    </View>

可用性小组是其中一名孩子

export const AvailabilityPanel: React.FunctionComponent<{}> = () => {
  const panel: Cell[][] = useSelector((state: ReduxStore) => {
    return get(state.entities, 'availability.panel', undefined)
  })

  if (panel === undefined) {
    return <Nothing />
  }

  return (
    <Section>
      <WhiteContainer>
        <LinearGradient
          start={{ x: 0, y: 0 }}
          end={{ x: 1, y: 0 }}
          colors={[Palette.White, Palette.White68]}
        >
          <View style={styles.rateContainer}>
            <DescriptionTextStatus
              statusText={strings.warning}
              descriptionText={strings.selectionMessage}
              icon={'clock'}
            />
            <View style={styles.separator} />
          </View>
          <View style={styles.container}>
            <ScrollView
              style={styles.scrollView}
              directionalLockEnabled={false}
              horizontal={true}
              showsHorizontalScrollIndicator={false}
              showsVerticalScrollIndicator={false}
            >
              <View style={styles.contentContainer}>
                <View style={styles.weekdaysContainer}>
                  <PanelHeader weekdays={weekdays} />
                </View>
                <View style={styles.rowsContainer}>
                  {hours.map((hourLabel: string, index: number) => {
                    return (
                      <PanelRow
                        key={index}
                        hourLabel={hourLabel}
                        hoursRow={panel[index]}
                        rowIndex={index}
                      />
                    )
                  })}
                </View>
              </View>
            </ScrollView>
          </View>
        </LinearGradient>
      </WhiteContainer>
    </Section>
  )
}

先谢谢了。

2 个答案:

答案 0 :(得分:3)

我认为保存scrollview的滚动位置的总体思路很好。

我认为您的状态重置为0的事实可能是由于Redux(但是不确定,您能否确定组件如何连接到redux?)。我对Hooks不太熟悉,但是在React Class组件中,我会尝试将滚动位置保存在该类的非state属性中。也许将其保存在功能组件之外的变量中?

然后在用于管理单元格更新的处理程序中,可以确保滚动视图滚动到保存的位置(使用ScrollView.scrollTo(){animated: false}选项,以便用户看不到动画)

答案 1 :(得分:2)

ScrollView不会由于子更新而重置滚动位置,无论您是否使用Redux。您无需尝试使用诸如保存当前滚动位置之类的变通办法对其进行修补。而是只是找出您的设置有什么问题

这很难说,因为您没有提供实际的代码,但是我很确定在更新时会重新安装一个或两个ScrollView(删除旧的ScrollView,并在新的位置创建一个单独的ScrollView)。 。您很可能在render函数中声明了新组件,因此React每次都会重新安装它们