You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native外部操作数据后,如何刷新列表组件?

问题解决:重置进度后组件不重新渲染

核心问题分析

  1. React状态更新依赖引用变化:直接修改gameData中的Puzzle对象属性(如item.unlocked = false),再调用setGameData(gameData)时,gameData的引用未改变,React判定状态无更新,不会触发组件重渲染。
  2. PuzzleCard本地状态与Context不同步:PuzzleCard自行维护unlocked本地state,但未监听Context中gameData的变化来同步状态。

具体修复步骤

1. 修复Context中的状态更新逻辑

在unlockPuzzle、loadProgress、resetProgress函数中,修改数据后需创建新的对象/数组引用,让React检测到状态变化:

export const GameContextProvider = ({ children } : { children: React.ReactNode }) => {
    const [gameData, setGameData] = useState<GameData>(jsonGameData)
    const [progressLoaded, setProgressLoaded] = useState(false);

    async function unlockPuzzle(item: Puzzle) {
        // 创建新数组,修改对应项的unlocked状态
        const updatedPuzzles = gameData.puzzles.map(puzzle => 
            puzzle.id === item.id ? { ...puzzle, unlocked: true } : puzzle
        );
        console.log("puzzle unlocked: " + JSON.stringify(item));
        return saveItemState("puzzle", item.id, true).then( () => {
            setGameData({ ...gameData, puzzles: updatedPuzzles });
        });
    };

    async function loadProgress() {      
        if(progressLoaded)
            return;
        console.log("loading progress");
        // 复制原数据避免直接修改原state
        const updatedGameData = { ...gameData };
        const promises = updatedGameData.puzzles.map((item : Puzzle) => {
            return loadItemState("puzzle", item.id).then(unlocked => {
                item.unlocked ||= unlocked;
                console.log("puzzle." + item.id + "=" + item.unlocked);
            });
        });      
        return Promise.all(promises).then(() => {
            setGameData(updatedGameData);
            setProgressLoaded(true);
        });
    };

    async function resetProgress() {
        console.log("reset progress");
        // 创建新数组,将所有项unlocked设为false
        const updatedPuzzles = gameData.puzzles.map(puzzle => 
            { ...puzzle, unlocked: false }
        );
        const promises = updatedPuzzles.map((item : Puzzle) => {
            return saveItemState("puzzle", item.id, item.unlocked);
        });
        return Promise.all(promises).then(() => {
            setGameData({ ...gameData, puzzles: updatedPuzzles });
        });
    };

    return  <GameContext.Provider value={{
                gameData,
                unlockHint,
                unlockPuzzle,
                loadProgress,
                resetProgress
            }}>
                {children}
            </GameContext.Provider>;
};

2. 修复PuzzleCard组件,同步Context状态

去掉PuzzleCard的本地unlocked状态,直接从Context获取最新数据(推荐):

export function PuzzleCard(props: PuzzleCardProps) {
    const { gameData, unlockPuzzle } = useContext(GameContext);
    const { item, ...otherProps } = props;  
    // 从gameData中获取最新的unlocked状态
    const currentPuzzle = gameData?.puzzles.find(p => p.id === item.id);
    const unlocked = currentPuzzle?.unlocked ?? false;

    const handlePress = function() {
        unlockPuzzle(item);
    };

    return  <Pressable onPress={handlePress} style={styles.card}>
                <Text style={styles.cardIcon}>{item.icon}</Text>
                <Text style={styles.cardState}>{unlocked ? "🔓" : "🔒"}</Text>
            </Pressable>;
}

3. 优化列表渲染的key值

避免用index作为列表项key,改用puzzle.id防止重置后渲染异常:

<View style={styles.container}>
    {gameData.puzzles.map((puzzle: Puzzle) => {
        return  <PuzzleCard key={puzzle.id} item={puzzle}/>
    })}
</View>

修复原理

  • React状态更新基于引用对比,只有状态引用变化时才会触发重渲染。通过创建新的数组/对象引用,让React检测到状态更新。
  • PuzzleCard直接依赖Context的最新数据,确保显示状态与Context数据同步。

内容的提问来源于stack exchange,提问作者ultimate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:05:39