【问题标题】:How to create a dynamic array of React hooks for an array of components如何为一组组件创建一个动态的 React 钩子数组
【发布时间】:2021-08-07 22:14:44
【问题描述】:
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 都是钩子,我无法遍历 prop 并为每个组件创建共享值和相应样式.

我怎样才能达到同样的效果?

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

【问题讨论】:

    标签: reactjs react-native react-native-reanimated-v2


    【解决方案1】:

    您可以使用visitIndex 值创建一个组件来处理每个项目的useSharedValueuseAnimatedStyle 挂钩:

    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 只能返回一个组件,并且必须将 components 数组包装起来。
    • 但这使得textScaleShared 变量位于另一个组件内。在减少文本比例的代码中,我有一个 setInterval 来循环每个组件的每个 textScaleShared 值并减少它们。我现在如何访问比例值?
    • @TopW3 是的,这没有什么问题,请参阅此工作示例stackblitz.com/edit/react-zcdqfq
    • @mohsinulhaq 您的代码缺少部分,您可以添加这些部分吗?
    • @mohsinulhaq 我更新了我的答案,我无法测试这段代码,但我认为你会想到创建一个组件来处理样式。
    【解决方案2】:

    您可以编写一个组件来为您处理它,但您需要传递您正在映射的文本的索引。

    这样

    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>
      ));
    }
    

    【讨论】:

      【解决方案3】:

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

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

      1. 多个组件 您可以拥有任意数量的组件,例如,每个组件都可以有一个钩子。
        const Text = ({ text }) => {
          // useSharedValue(1)
          // useAnimatedStyle
        }
      
        const Components = ({ texts }) => {
          return texts.map(text => <Text text={text} />)
        }
      
      1. 单钩 也可以看看能不能找到一个可以同时适用于所有组件的className。我假设是 css。

      【讨论】:

        猜你喜欢
        • 2020-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-15
        • 1970-01-01
        • 2018-02-26
        • 1970-01-01
        相关资源
        最近更新 更多