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

React Native中useCallback获取state始终返回初始值的问题

问题原因及解决方法

原因

  1. 闭包捕获旧状态:useCallback依赖数组为空时,renderItem函数会被缓存,内部始终引用组件初始渲染时的todos(空数组),所以console.log(todos.length)始终输出0。
  2. 列表组件复用导致旧闭包残留:即便添加todos或todos.length到依赖数组,FlashList的列表项复用机制会让已渲染的项保留旧的onPress闭包,依旧读取旧状态值。

解决方法

方法一:利用函数式更新获取最新状态

既然setTodos已经使用函数式更新获取当前状态,直接把长度判断逻辑移到setTodos的回调里,无需依赖外部todos,同时简化useCallback的依赖:

export default function MyComponent() {
  const [todos, setTodos] = useState<string[]>([]);
  const renderItem = useCallback(
    ({ item }: ListRenderItemInfo<Todo>) => (
      <TouchableOpacity
        style={{ height: 50 }}
        onPress={() => {
          setTodos((curr) => {
            console.log(curr.length); // 获取最新状态长度
            if (curr.length >= 10) return curr;
            return [item.name, ...curr];
          });
        }}
      >
        <Heading color="black">{item.name}</Heading>
      </TouchableOpacity>
    ),
    [] // 无需依赖todos
  );

  return (
    <FlashList<Todo>
      data={data?.todos as Todo[]}
      estimatedItemSize={50}
      renderItem={renderItem}
      keyExtractor={(_, idx) => idx.toString()}
    />
  );
}

方法二:用useRef保存最新状态

通过useRef实时同步todos的最新值,突破闭包限制,直接读取最新状态:

export default function MyComponent() {
  const [todos, setTodos] = useState<string[]>([]);
  const todosRef = useRef<string[]>([]);

  // 状态更新时同步到ref
  useEffect(() => {
    todosRef.current = todos;
  }, [todos]);

  const renderItem = useCallback(
    ({ item }: ListRenderItemInfo<Todo>) => (
      <TouchableOpacity
        style={{ height: 50 }}
        onPress={() => {
          const currentLength = todosRef.current.length;
          console.log(currentLength); // 获取最新长度
          if (currentLength >= 10) return;
          setTodos((curr) => [item.name, ...curr]);
        }}
      >
        <Heading color="black">{item.name}</Heading>
      </TouchableOpacity>
    ),
    [] // 无需依赖todos
  );

  return (
    <FlashList<Todo>
      data={data?.todos as Todo[]}
      estimatedItemSize={50}
      renderItem={renderItem}
      keyExtractor={(_, idx) => idx.toString()}
    />
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 15:42:50