У меня есть два компонента списка или стопки карточек. 5 колод и несколько карт в каждой колоде. Я перечисляю 5 колод и передаю их содержимое дочернему компоненту, когда нажимаю на него в состоянии (selectedItem). Затем я беру это в дочернем компоненте и сопоставляю другой плоский список с карточками внутри.
Моя проблема в том, что когда я нажимаю на индекс, выходящий за пределы меньшей колоды. Например,
Deck1 = 23 cards
Deck2 = 15 cards
Когда я индексирую +1 на Deck1 где-то выше 15 и пытаюсь нажать на Deck2, он говорит, что он вне диапазона (очевидно, лол), я бы хотел, чтобы он сбрасывался до index(0) при смене колод. Я не могу просто добавить больше карт и сделать их одинаковым количеством, потому что позже я устанавливаю новую функцию, где пользователь может создать свою собственную колоду, и это может быть любое количество карт.
Вот мой компонент Decks
const Decks = () => {
const {theme} = useContext(ThemeContext)
let activeColors = colors[theme.mode]
const allbelts = [yellowbelt, orangebelt, greenbelt, brownbeltthree, brownbelttwo, brownbeltone]
const ref = useRef(null);
const [selectedItem, setSelectedItem] = useState(null);
const [deckIndex, setDeckIndex] = useState(0);
const handleItemPress = (item) => {
setSelectedItem(item);
console.info("deckIndex:", deckIndex);
};
return (
<View style = {{flex:1}}>
<View style = {{flex:1, marginTop: 40}}>
<Text style = {[{color:activeColors.primary}, styles.sectionheading]}>
Testing Card Decks
</Text>
<Animated.FlatList
ref = {ref}
data = {allbelts}
horizontal
keyExtractor = {(item, index) => index.toString()}
showsHorizontalScrollIndicator = {false}
snapToInterval = {ITEM_SIZE}
decelerationRate = {0}
bounces = {false}
scrollEventThrottle = {16}
renderItem = {({item, deckIndex}) => (
<View
style = {{}}>
<TouchableOpacity
key = {deckIndex}
onPress = {() => {
handleItemPress(item)
}}>
<Animated.View
style = {[{
backgroundColor: item.color,
shadowColor: item.color,
borderColor: activeColors.bgalt},
styles.card]}>
<Text
numberOfLines = {2}
style = {[{color: item.color === "#F5D143" ? activeColors.black : activeColors.white}, styles.cardtitle]}>
{item.rank_japanese}
</Text>
<Text
numberOfLines = {2}
style = {[{color: item.color === "#F5D143" ? activeColors.black : activeColors.white}, styles.cardtitle]}>
{item.rank_english}
</Text>
</Animated.View>
</TouchableOpacity>
</View>
)}
/>
<Cards selectedItem = {selectedItem} deckIndex = {deckIndex} />
</View>
</View>
)
}
export default Decks
а вот компонент «Карты»
const Card = ({info}) => {
const {theme} = useContext(ThemeContext)
let activeColors = colors[theme.mode]
const rotate = useSharedValue(0);
const frontAnimatedStyle = useAnimatedStyle(() => {
const rotateValue = interpolate(
rotate.value,
[0, 1],
[0, 180]
);
return {
transform: [
{rotateY: withTiming(`${rotateValue}deg`, {duration: 500})}
]
}
})
const backAnimatedStyle = useAnimatedStyle(() => {
const rotateValue = interpolate(
rotate.value,
[0, 1],
[180, 360]
);
return {
transform: [
{rotateY: withTiming(`${rotateValue}deg`, {duration: 500})}
]
}
})
return (
<View style = {[styles.cardcontainer]}>
<View style = {styles.iconcnt}>
<Pressable
onPress = {() => {
rotate.value = rotate.value ? 0 : 1;
}}
style = {styles.icon}>
<Icon name = "swap-horizontal" size = {24} color = {activeColors.textcolor} />
</Pressable>
</View>
<View style = {styles.cardContent}>
<Animated.View style = {[ {backgroundColor: activeColors.bgalt, position:"absolute"}, styles.card, frontAnimatedStyle]}>
<View>
<Text
style = {[{color: activeColors.textcolor}, styles.cardtext]}>
{info.q}
</Text>
</View>
</Animated.View>
<Animated.View style = {[ {backgroundColor: activeColors.primary}, styles.card, backAnimatedStyle]}>
<View>
<Text
style = {[{color: activeColors.textcolor}, styles.cardtext]}>
{info.a}
</Text>
</View>
</Animated.View>
</View>
</View>
)
}
const Cards = ({selectedItem, deckIndex}) => {
const {theme} = useContext(ThemeContext)
let activeColors = colors[theme.mode]
const [index, setIndex] = useState(0);
const [lastIndex, setLastIndex] = useState(null);
const [viewPosition, setViewPosition] = useState(0.5);
const flatlistRef = useRef(null)
useEffect(() => {
setLastIndex(selectedItem?.questions?.length - 1);
// console.info("selectedItem:", selectedItem);
console.info("lastIndex at TestingCards:", lastIndex);
flatlistRef.current?.scrollToIndex({
index: index,
animated: true,
viewPosition,
})
} , [index, viewPosition, lastIndex, selectedItem])
if (!selectedItem) {
return null;
}
return (
<View style = {[styles.container]}>
<Animated.FlatList
data = {selectedItem.questions}
ref = {flatlistRef}
index = {deckIndex}
keyExtractor = {(item, index) => index.toString()}
initialScrollIndex = {0}
horizontal
showsHorizontalScrollIndicator = {false}
snapToInterval = "ITEM_SIZE"
decelerationRate = {0}
bounces = {false}
scrollEventThrottle = {16}
initialNumToRender = {10}
onScrollToIndexFailed = {index => {
setIndex(0)
const wait = new Promise(resolve => setTimeout(resolve, 0));
wait.then(() => {
flatlistRef.current?.scrollToIndex({ index: index, animated: true });
});
}}
renderItem = {({item, index}) => <Card info = {item} index = {index} totalLength = {lastIndex} seefront = {true} />}
/>
<View style = {styles.btnGroup}>
<TouchableOpacity
onPress = {()=>{
setIndex(0);
setViewPosition(0.5);
}}>
<LinearGradient
colors = {['rgba(1,102,175,1)', 'rgba(155,24,213,1)']}
start = {{ x: 0, y: 1 }}
end = {{ x: 1, y: 1 }}
style = {styles.btnPrimary}>
<Icon name = "chevron-double-left" size = {24} color = {activeColors.white} />
</LinearGradient>
</TouchableOpacity>
<TouchableOpacity
onPress = {()=>{
if (index === 0) {
return;
}
setIndex(index - 1);
setViewPosition(0.5);
}}>
<LinearGradient
colors = {['rgba(1,102,175,1)', 'rgba(155,24,213,1)']}
start = {{ x: 0, y: 1 }}
end = {{ x: 1, y: 1 }}
style = {styles.btnPrimary}>
<Icon name = "chevron-left" size = {24} color = {activeColors.white} />
</LinearGradient>
</TouchableOpacity>
<TouchableOpacity
onPress = {()=>{
if (index === lastIndex) {
return;
}
setIndex(index + 1);
setViewPosition(0.5);
}}>
<LinearGradient
colors = {['rgba(1,102,175,1)', 'rgba(155,24,213,1)']}
start = {{ x: 0, y: 1 }}
end = {{ x: 1, y: 1 }}
style = {styles.btnPrimary}>
<Icon name = "chevron-right" size = {24} color = {activeColors.white} />
</LinearGradient>
</TouchableOpacity>
<TouchableOpacity
onPress = {()=>{
if (index === lastIndex) {
return;
}
setIndex(lastIndex - 1);
setViewPosition(0.5);
}}>
<LinearGradient
colors = {['rgba(1,102,175,1)', 'rgba(155,24,213,1)']}
start = {{ x: 0, y: 1 }}
end = {{ x: 1, y: 1 }}
style = {styles.btnPrimary}>
<Icon name = "chevron-double-right" size = {24} color = {activeColors.white} />
</LinearGradient>
</TouchableOpacity>
</View>
</View>
)
}
export default Cards



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


useEffect(() => {
flatlistRef.current?.scrollToIndex({
index: index,
animated: true,
viewPosition,
})
} , [index])
useEffect(()=>{
setIndex(0)
setLastIndex(selectedItem?.questions?.length - 1);
setViewPosition(0.5)
}, [selectedItem])
Он сбрасывает индекс в 0 всякий раз, когда изменяется DeckIndex, и, с другой стороны, всякий раз, когда вы выбираете другую колоду. Вы можете добавить несколько кодов для сброса других вещей внутри useEffect.
Обновлять:
initialNumToRender = {selectedItem.questions.length}
Это понадобится в FlatList, чтобы избежать ошибки ScrollToIndex.
Это не помогло. Я не был уверен, в каком компоненте это будет установлено, поэтому я сделал это в компоненте карточек, в котором находится setIndex, и он просто переключался между первыми двумя картами в выбранной колоде вперед и назад. Очень странно. Затем я попробовал это на родительском компоненте, и это ничего не изменило.
Чтобы ответить на ваш вопрос выше, компонент FlashCards был переименован, когда я копировал код, извините. Я отредактировал свой ОП. По сути, компонент Decks — это то, что заполняет маршрут. Он принимает компонент Cards, а компонент Cards отображает коллекцию компонента Card.
Да, его следует поместить в компонент карточек. Я обновил условие useEffect.
Оооо, почти получилось!!!! Когда я сменил колоду, он вернулся к индексу 0, но ошибка возникает до того, как он устанавливает индекс Invariant Violation: scrollToIndex out of range: requested index 23 is out of 0 to 22
на самом деле нет смысла в viewPosition и LastIndex, поскольку нет изменения viewPosition и нет использования LastIndex. поэтому вам не нужно объявлять их как состояние.
Да, это все еще не работает. Я могу щелкнуть другую колоду, и она вернется к индексу 0, но если состояние имеет более высокий индекс, чем тот, который я нажимаю в данный момент, поскольку я запрашиваю индекс + 1, он терпит неудачу, если не находит это. Скажем, например, я пришел из индекса 23. Когда я вызываю индекс +1, он ожидает индекс 24. Я чувствую, что знаю это, но не могу заставить свой код делать то, что у меня в голове.
Если вы хотите, чтобы ваш код работал полностью, вам потребуется отладить ваш код с использованием реальных данных. Надеюсь, вы понимаете, как использовать хук и состояние useEffect.
Да, это гоночное состояние. Но я посмотрю, смогу ли я реализовать это в каком-нибудь онлайн-редакторе.
Было бы лучше, если бы можно было поделиться полным кодом.
Код заполнения находится в этом вопросе. Я не могу добавить его в закуску, потому что он не запускается из-за других зависимостей.
Есть ли репозиторий, загруженный на git?
да. Я могу добавить вас в него по вашему желанию. Какой у тебя дескриптор на GitHub? Я отправлю приглашение. Я не могу отблагодарить тебя, чувак
Я повышу свой вопрос до награды и дам вам ответ, чтобы вы получили еще большую шишку
Идентификатор GitHub: jonasbeckdev
Приглашение отправлено....
Он работает на эмуляторе. но я не могу найти подходящие компоненты, скорее всего, нет компонентов с названиями «Колоды» и «Карта».
Я только что объединил свой последний код. Я забыл, что не делал этого. Извини. Оформить заказ снова и git pull
Давайте продолжим обсуждение в чате.
где используются FlashCards?