如何为组件数组创建React hooks的动态数组

4
const AnimatedText = Animated.createAnimatedComponent(Text);

function Component({ texts }) {
  const [visitIndex, setVisitIndex] = React.useState(0);

  // can't create an array of shared value for each text
  // since useSharedValue is a hook, and that throws a warning
  const textScalesShared = texts.map((_) => useSharedValue(1));

  // can't create an array of animated style for each text
  // since useAnimatedStyle is a hook, and that throws a warning
  const animatedTextStyle = textScalesShared.map((shared) =>
    useAnimatedStyle(() => ({
      transform: [{ scale: shared.value }],
    }))
  );

  useEffect(() => {
    // code to reduce text scale one after another
    // it will loop over the array of textScaleShared values
    // passed to each component and update it
    if (visitIndex === texts.length) {
      return;
    }

    textScalesShared[visitIndex].value = withDelay(
      1000,
      withTiming(0.5, {
        duration: 1000,
      })
    );

    const timerId = setTimeout(() => {
      setVisitIndex((idx) => idx + 1);
    }, 1000);

    return () => {
      clearTimeout(timerId);
    };
  }, [visitIndex]);

  return texts.map((text, index) => {
    if (index <= visitIndex) {
      return (
        <AnimatedRevealingText
          key={index}
          fontSize={fontSize}
          revealDuration={revealDuration}
          style={animatedStylesShared[index]}
          {...props}
        >
          {text}
        </AnimatedRevealingText>
      );
    } else {
      return null;
    }
  });
}

我希望能给一组组件应用动画样式,但是由于useSharedValueuseAnimatedStyle都是hooks,因此我无法遍历props并为每个组件创建共享值和相应的样式。

我该如何实现同样的效果?

编辑:已更新以添加完整代码。

3个回答

3
你可以创建一个组件来处理每个项目的useSharedValueuseAnimatedStyle 钩子,使用visitIndex值: AnimatedTextItem.js
const AnimatedText = Animated.createAnimatedComponent(Text);

const AnimatedTextItem = ({text, visited}) => {
  const textScaleShared = useSharedValue(1);
  const style = useAnimatedStyle(() => ({
    transform: [{ textScaleShared.value }],
  }));

  useEffect(()=> {
    if(visited) {
      textScaleShared.value = withDelay(
        1000,
        withTiming(0.5, {
          duration: 1000,
        });
      );
    }
  }, [visited]);
  
  return (<AnimatedText style={style}>{text}</AnimatedText>)
}

Component.js

function Component({texts}) {
  const [visitIndex, setVisitIndex] = React.useState(0);

  useEffect(() => {
    // code to reduce text scale one after another
    // it will loop over the array of textScaleShared values
    // passed to each component and update it
    if (visitIndex === texts.length) {
      return;
    }

    const timerId = setTimeout(() => {
      setVisitIndex((idx) => idx + 1);
    }, revealDuration);

    return () => {
      clearTimeout(timerId);
    };
  }, []);
  return texts.map((text, index) => (<AnimatedTextItem text={text} visited={visitIndex === index}/>))
}

React 只能返回一个组件,你必须将组件数组包装起来。 - TopW3
但这会使textScaleShared变量位于另一个组件内部。在减小文本比例的代码中,我有一个setInterval循环遍历每个组件的textScaleShared值并将它们减小。现在我该如何访问比例值? - mohsinulhaq
@TopW3 是的,这没有任何问题,可以看看这个工作示例 https://stackblitz.com/edit/react-zcdqfq - lissettdm
@mohsinulhaq,你的代码有缺失部分,请添加这些部分。 - lissettdm
1
@mohsinulhaq 我更新了我的回答,我无法测试这段代码,但我认为你会理解如何创建一个组件来处理样式。 - lissettdm

1
你可以编写一个组件来处理它,但是你需要传递正在映射的文本的索引。
像这样:
const AnimatedText = ({styleIndex}) => {
  const textScaleShared = useSharedValue(styleIndex + 1);

  const animatedTextStyle = useAnimatedStyle(() => ({
    transform: [{ scale: textScaleShared.value }],
  }));
  
  const Animated = Animated.createAnimatedComponent(Text);

  return <Animated style={animatedTextStyle}>{text}</Animated>;
};

function Component({ texts }) {
  useEffect(() => {
    // code to reduce text scale one after another
  }, []);

  return texts.map((text, index) => (
    <AnimatedText key={index} styleIndex={index}>
      {text}
    </AnimatedText>
  ));
}

0

有趣的问题 :) 让我看看能否想出一个解决方案。

您已经注意到hook不能在动态数组中,因为数组的长度是未知的。

  1. 多个组件 您可以拥有尽可能多的组件,每个组件都可以有一个钩子,例如:
  const Text = ({ text }) => {
    // useSharedValue(1)
    // useAnimatedStyle
  }

  const Components = ({ texts }) => {
    return texts.map(text => <Text text={text} />)
  }

2. 单个钩子 您还可以查看是否可以找到一个适用于所有组件的className。我想这是CSS相关的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接