В моем проекте React Native (v0.81.0) + Redux (v5.0.1) + Reanimated (v4.0.2) у меня есть компонент свай, который представляет игровой кусок. Предполагается, что произведение обновляет свою позицию на основе Piece.pos из магазина Redux. Однако пользовательский интерфейс не отражает это сброс должным образом. В частности: < /p>
- Компоненты ски не возвращаются в свою базовую позицию (сюжет [pieceId]) после сброса. < /Li>
Несмотря на то, что состояние Redux показывает POS = 0 для всех частей, кусочки остаются на своих старых позициях. и обновление Transtatex/Transtatey соответственно. Для POS = 0, он должен немедленно установить координаты из сюжета [pieceID], но этот переход не происходит.Код: Выделить всё
import { Image, TouchableOpacity, View } from 'react-native'; import React, { useCallback, useEffect, useMemo } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import Animated, { useSharedValue, useAnimatedStyle, withTiming, } from 'react-native-reanimated'; import { AppDispatch, RootState } from '../redux/store'; import { Colors, ColorType } from '../constants/Colors'; import PileGreen from '../assets/images/piles/green.png'; import PileRed from '../assets/images/piles/red.png'; import PileYellow from '../assets/images/piles/yellow.png'; import PileBlue from '../assets/images/piles/blue.png'; import { PlayerKey } from './Dice'; import RotatingDashedCircle from './RotatingDashedCircle'; import { selectCellMap, selectCellSelectionPlayer, selectCurrentPlayerChance, selectCurrentPositions, selectDiceNo, selectPlotCellMap, selectPocketPileSelectionPlayer, } from '../redux/reducers/gameSelectors'; import { handlePileForwardThunk } from '../redux/reducers/gameAction'; import { victoryPoints } from '../helpers/PlotData'; interface PileProps { pieceId: string; player: number; color: ColorType; } const Pile = ({ pieceId, player, color }: PileProps) => { const dispatch = useDispatch(); const cellMap = useSelector(selectCellMap); const plotMap = useSelector(selectPlotCellMap); const diceNo = useSelector(selectDiceNo); const currentPlayerPileSelection = useSelector( selectPocketPileSelectionPlayer, ); const currentPlayerCellSelection = useSelector(selectCellSelectionPlayer); const currentPlayerChance = useSelector(selectCurrentPlayerChance); const playerPieces = useSelector( (state: RootState) => state.game[`player${player}` as PlayerKey], ); const allPlayerPieces = useSelector(selectCurrentPositions); const piece = playerPieces?.find(p => p.id === pieceId)!; const currentCell = piece.pos !== 0; // Initialize position from plotMap (base position) or cellMap (board position) const getCoordinates = useCallback( (pos: number) => { return pos === 0 ? plotMap[pieceId] : cellMap[pos]; }, [plotMap, cellMap, pieceId], ); const initialCoords = getCoordinates(piece.pos); const translateX = useSharedValue(initialCoords?.x ?? 0); const translateY = useSharedValue(initialCoords?.y ?? 0); const scale = useSharedValue(1); const isPileEnabled = player === currentPlayerPileSelection; const isCellEnabled = player === currentPlayerCellSelection; const isForwardable = useCallback(() => { const pilePiece = playerPieces?.find(item => item.id === pieceId)!; return !!pilePiece && pilePiece.travelCount + diceNo { const coords = getCoordinates(piece.pos); if (coords) { // For reset to base (pos === 0), move immediately without animation if (piece.pos === 0) { translateX.value = coords.x; translateY.value = coords.y; } else { // For board movement, use smooth animation translateX.value = withTiming(coords.x, { duration: 300 }); translateY.value = withTiming(coords.y, { duration: 300 }); } } }, [piece.pos, getCoordinates]); // Track previous position to detect changes and play sound // Simplified handlePress - only dispatches the action const handlePress = async () => { if (!piece) return; // Simply dispatch the thunk - movement will be handled by useAnimatedReaction await dispatch(handlePileForwardThunk(player, pieceId)); }; const sameCellPieces = allPlayerPieces.filter( p => p.pos === piece.pos && piece.pos !== 0, ); const stackIndex = sameCellPieces.findIndex(p => p.id === pieceId); const stackOffset = stackIndex !== -1 ? stackIndex * 8 : 0; // Update scale on player turn useEffect(() => { const isHome = victoryPoints.includes(piece.pos); if (isHome && sameCellPieces.length > 1) { scale.value = withTiming(0.7, { duration: 200 }); return } if ( (currentPlayerChance === player && isCellEnabled) || piece.pos === 0 || sameCellPieces.length < 2 ) { scale.value = withTiming(1, { duration: 200 }); } else { scale.value = withTiming(0.7, { duration: 200 }); } }, [ currentPlayerChance, sameCellPieces.length, piece.pos, scale, player, isCellEnabled, ]); // Animated style const animatedStyle = useAnimatedStyle(() => ({ transform: [ { translateX: translateX.value + stackOffset }, { translateY: translateY.value }, { scale: scale.value }, ], })); const pileImages: Record = { [Colors.green]: PileGreen, [Colors.red]: PileRed, [Colors.yellow]: PileYellow, [Colors.blue]: PileBlue, }; const pileImage = useMemo(() => pileImages[color], [color]); return ( {currentCell ? isCellEnabled && isForwardable() && : isPileEnabled && } ); }; export default Pile; < /code> winmodal.tsx, где Redux ResetGame отправляется для обновления состояния игры до начального состояния.import { View, Text, StyleSheet } from 'react-native' import React, { JSX, useEffect, useState } from 'react' import { announceWinner, resetGame } from '../redux/reducers/gameSlice'; import { navigate } from '../helpers/NavigationUtil'; import { playSound, stopAllSounds } from '../helpers/SoundUtility'; import { useDispatch } from 'react-redux'; import Modal from 'react-native-modal'; import LinearGradient from 'react-native-linear-gradient'; import LottieView from 'lottie-react-native'; import Trophy from '../assets/animation/trophy.json'; import Firework from '../assets/animation/firework.json'; import HeartGirl from '../assets/animation/girl.json' import GradientButton from './GradientButton'; import Token from './Token'; import { ColorPlayer } from '../helpers/PlotData'; interface WinModalProps { winner: number | null ; } const WinModal = ({winner}:WinModalProps): JSX.Element => { const dispatch = useDispatch(); const [visible, setVisible] = useState(!!winner); const handleNewGame = () => { dispatch(resetGame()); stopAllSounds() dispatch(announceWinner(null)); playSound('game_start'); }; const handleHome = () => { dispatch(resetGame()); stopAllSounds(); dispatch(announceWinner(null)); navigate('HomeScreen'); } useEffect(() => { setVisible(!!winner); // playSound("cheer") },[winner]) return ( {winner !== null && ( )} Congratulations! Player {winner} ); } const style = StyleSheet.create({ trophy: { height: 200, width: 200, marginTop: 20, }, firework: { height: 200, width: 500, position: 'absolute', marginTop: 20, zIndex: 1, }, heartGirl: { height: 500, width: 380, position: 'absolute', bottom: -200, right: -120, zIndex: 99, }, }); export default WinModal < /code> Это Resetgame Reducer и начальный стат resetGame: () => initialState,
export type RootPlayerTokenState = {
id: string;
pos: number;
travelCount: number;
};
export type CellPosition = { x: number; y: number };
export type CellState = Record;
export type PlotState = Record;
const player1InitialState = [
{ id: 'A1', pos: 0, travelCount: 0 },
{ id: 'A2', pos: 0, travelCount: 0 },
{ id: 'A3', pos: 0, travelCount: 0 },
{ id: 'A4', pos: 0, travelCount: 0 },
];
const player2InitialState = [
{ id: 'B1', pos: 0, travelCount: 0 },
{ id: 'B2', pos: 0, travelCount: 0 },
{ id: 'B3', pos: 0, travelCount: 0 },
{ id: 'B4', pos: 0, travelCount: 0 },
];
const player3InitialState = [
{ id: 'C1', pos: 0, travelCount: 0 },
{ id: 'C2', pos: 0, travelCount: 0 },
{ id: 'C3', pos: 0, travelCount: 0 },
{ id: 'C4', pos: 0, travelCount: 0 },
];
const player4InitialState = [
{ id: 'D1', pos: 0, travelCount: 0 },
{ id: 'D2', pos: 0, travelCount: 0 },
{ id: 'D3', pos: 0, travelCount: 0 },
{ id: 'D4', pos: 0, travelCount: 0 },
];
export const initialState = {
player1: player1InitialState,
player2: player2InitialState,
player3: player3InitialState,
player4: player4InitialState,
chancePlayer: 1,
diceNo: 1,
isDiceRolled: false,
pileSelectionPlayer: -1,
cellSelectionPlayer: -1,
touchDiceBlock: false,
currentPositions: [] as RootPlayerTokenState[],
fireworks: false,
winner: null as number | null,
cellMap: {} as CellState,
PlotMap: {} as PlotState,
resetCounter:1
};
< /code>
Я не знаю фактической причины, по которой куча застряла при отправке Resetgame Reducer, но я предоставил все вещи. 0). < /Li>
< /ul>
фактическое поведение < /strong> < /p>
Состояние Redux сбрасывается правильно. < /Li>
UI не обновляется; Сваи остаются застрявшими на своей последней позиции доски.
Подробнее здесь: https://stackoverflow.com/questions/797 ... tate-reset
Мобильная версия