刷新列表时挂钩 useCallback 继续使用旧值

Ron*_*tro 6 javascript reactjs react-native react-hooks

下面的 useCallback 有什么问题,每次onRefresh调用函数时我都没有得到下面的值?我怎样才能让它返回预期值using Hooks

当我调用 onRefresh 2x 时的示例

预期值:

true
0
20
false

true
0
20
false
Run Code Online (Sandbox Code Playgroud)

值:收到

false
0
0
false

false
20
20
false
Run Code Online (Sandbox Code Playgroud)

状态变量的初始化

const [refreshing, setRefreshing] = useState(false)
const [offsetQuestions, setOffsetQuestions] = useState(0)
Run Code Online (Sandbox Code Playgroud)

使用 useCallback 调用函数:

const fetchSomeData = async () => {
  await new Promise(resolve => setTimeout(resolve, 3000)) // 3 sec
}

const onRefresh = useCallback( async () => {
  setRefreshing(true)
  setOffsetQuestions(0)
  console.log(refreshing)
  console.log(offsetQuestions)

  await fetchSomeData()

  setOffsetQuestions(20)
  setRefreshing(false)
  console.log(offsetQuestions)
  console.log(refreshing)
}, [refreshing, offsetQuestions])
Run Code Online (Sandbox Code Playgroud)

函数被调用的地方:

<FlatList
   data={questionsLocal}
   refreshing={refreshing}
   onRefresh={onRefresh}
   ...
/>
Run Code Online (Sandbox Code Playgroud)

小智 9

您得到的是钩子中的预期行为。这都是关于关闭的。React 中的每个渲染都有自己的 props、状态、函数和事件处理程序,并且对于该特定渲染它们永远保持不变。所以这里发生的事情是, 正在useCallback关闭特定渲染的状态变量,因此,由于关闭console.log, a 后的偶数setState将始终为您提供该特定渲染的状态值。


gil*_*ran 6

这种情况让很多开始使用 hooks 的开发人员感到困惑。你会期望 React 会是响应式的,并且会在你调用之后改变状态的值setX,但如果您考虑一下,您不能期望 React 停止执行流程更改状态变量并继续执行。

因此,您得到的是来自创建范围的状态变量useCallback(请反复阅读)。

让我们将其分为两部分:作用域和 useCallback,因为这是两个不同的东西,您必须理解才能使用useStateuseCallback

范围:

假设您有一个名为的状态age和一个写入/读取该状态的函数(目前,不使用useCallback

const [age, setAge] = useState(42);

const increaseAge = () => {
  setAge(age + 1);   // this "age" is the same "age" from above 
  console.log(age);  // also this one
}
Run Code Online (Sandbox Code Playgroud)

从这里你可以看到,每个渲染都age定义了一个新变量(如果是由 React 给出的值),还increaseAge定义了一个新函数,可以访问保存该变量的范围age变量的范围。

age这就是作用域的工作方式,这就是为什么在调用 后不会立即获得新值 的原因setAge。为了能够在ageReact 上获取新值,必须重新渲染组件,因此age将在新作用域上定义一个新变量。而这正是调用后发生的情况setAge,React 将触发新的渲染。

使用回调

现在,假设您不想increaseAge一次又一次地定义该函数,您想保留相同的引用(可以帮助防止无用的渲染)。这就是您想要使用的地方useCallback

使用 时useCallback,React 为每个渲染提供相同的函数引用,除非依赖项之一发生更改。

如果不提供useCallback依赖项,React 将不会重新创建该函数,并且该函数将访问创建它的范围(第一次渲染),当提供useCallback正确的依赖项时,它将重新创建,并且现在可以访问该范围最新的状态变量。

这应该解释为什么必须提供依赖项,以及如何访问状态变量(范围)。