如何为组件数组创建一个动态的 React 钩子数组
How to create a dynamic array of React hooks for an array of components
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;
}
});
}
我想将动画样式应用于组件数组,但由于 useSharedValue
和 useAnimatedStyle
都是 hook,我无法遍历 prop 并创建共享值和相应的每个组件的样式。
我怎样才能达到同样的效果?
编辑:已更新以添加完整代码。
您可以创建一个组件来处理每个使用 visitIndex
值的项目的 useSharedValue
和 useAnimatedStyle
挂钩:
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}/>))
}
您可以编写一个组件来为您处理它,但您需要传递要映射的文本的索引。
像这样
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>
));
}
有趣的问题 :) 让我看看我能否想出一个解决方案。
您已经注意到 hook
不能在动态数组中,因为数组的长度未知。
- 多个组件
您可以拥有任意数量的组件,每个组件都可以有一个钩子,例如。
const Text = ({ text }) => {
// useSharedValue(1)
// useAnimatedStyle
}
const Components = ({ texts }) => {
return texts.map(text => <Text text={text} />)
}
- 单钩
您还可以查看是否可以找到一个可以同时应用于所有组件的类名。我猜是 css。
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;
}
});
}
我想将动画样式应用于组件数组,但由于 useSharedValue
和 useAnimatedStyle
都是 hook,我无法遍历 prop 并创建共享值和相应的每个组件的样式。
我怎样才能达到同样的效果?
编辑:已更新以添加完整代码。
您可以创建一个组件来处理每个使用 visitIndex
值的项目的 useSharedValue
和 useAnimatedStyle
挂钩:
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}/>))
}
您可以编写一个组件来为您处理它,但您需要传递要映射的文本的索引。
像这样
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>
));
}
有趣的问题 :) 让我看看我能否想出一个解决方案。
您已经注意到 hook
不能在动态数组中,因为数组的长度未知。
- 多个组件 您可以拥有任意数量的组件,每个组件都可以有一个钩子,例如。
const Text = ({ text }) => {
// useSharedValue(1)
// useAnimatedStyle
}
const Components = ({ texts }) => {
return texts.map(text => <Text text={text} />)
}
- 单钩 您还可以查看是否可以找到一个可以同时应用于所有组件的类名。我猜是 css。