React Native Skia绘图应用状态异常:仅保留最后一条路径
React Native Skia画布无法保存多路径的问题解决
问题核心原因
- 闭包陷阱导致状态捕获失效:你使用的
useCallback都未添加依赖数组,比如savePaths里引用了paths但未将其加入依赖,导致回调始终捕获组件初始化时的空paths数组,每次保存都是在空数组基础上新增,直接覆盖之前的状态。 - 临时路径用普通变量无法持久化:
workingPath是普通let变量,组件每次重新渲染(比如状态更新后)都会重置该变量,逻辑上存在隐患,应该用useRef保存,因为ref.current在组件生命周期内不会被重置。 - 冗余的
displayPaths状态:没必要将JSX元素存入状态,直接在渲染阶段映射paths数组即可,状态只负责存储数据,渲染逻辑放在render阶段更合理。
修改后的完整代码
import { Canvas, Path, Group, useTouchHandler, } from "@shopify/react-native-skia"; import { useState, useRef, useCallback } from 'react'; export const StateTest = () => { // 用useRef保存临时路径,避免组件渲染时重置 const workingPathRef = useRef<string[]>([]); const [paths, setPaths] = useState<string[]>([]); const onDrawingStart = useCallback(({ x, y }) => { workingPathRef.current = [`M ${x} ${y}`]; }, []); const onDrawingActive = useCallback(({ x, y }) => { if (!workingPathRef.current) { return; } workingPathRef.current.push(`L ${x} ${y}`); }, []); const onDrawingFinished = useCallback(() => { if (!workingPathRef.current || workingPathRef.current.length === 0) { return; } // 用函数式更新获取最新状态,彻底规避闭包问题 setPaths(prevPaths => [...prevPaths, workingPathRef.current.join(" ")]); workingPathRef.current = []; }, []); const touchHandler = useTouchHandler({ onActive: onDrawingActive, onStart: onDrawingStart, onEnd: onDrawingFinished, }); return ( <Canvas style={{ flex: 1 }} onTouch={touchHandler}> <Group> {/* 直接在渲染阶段映射paths数组 */} {paths.map((p, index) => ( <Path key={index} path={p} color="red" style="stroke" strokeWidth={4} /> ))} </Group> </Canvas> ); };
关键修改说明
- 替换
workingPath为useRef:确保临时绘制路径在组件多次渲染中不会丢失。 - 使用函数式更新
setPaths:通过prevPaths获取最新状态,彻底避免闭包导致的旧状态引用问题,无需依赖paths。 - 移除冗余状态与副作用:删掉
displayPaths相关的状态、drawPaths函数和useEffect,直接在Canvas中渲染paths,简化逻辑。 - 补全
useCallback依赖数组:确保回调函数的稳定性,符合React Hooks的规则。
内容的提问来源于stack exchange,提问作者cbolton
相关产品推荐
相关产品推荐

