React refs 在 useCallback 中如何表现?
How do React refs behave inside useCallback?
我不希望以下 React 应用程序正常工作,但它确实如此。我希望 useCallback 挂钩捕获并保留 ref 的初始值。我知道 ref 不能列在依赖项数组中,所以这可能是一个仅用于 refs 的特殊情况?
为什么 newTodoRef.current.value 的内容在 App 首次渲染时不被 useCallback 捕获一次?
import React, { useCallback, useReducer, useRef } from 'react';
type Todo = { id: number, text: string }
type ActionType = { type: 'ADD', text: string} | { type: 'REMOVE', id: number}
const todoReducer = (state: Todo[], action: ActionType) => {
switch(action.type) {
case 'ADD': return [ ...state, { id: state.length, text: action.text }]
case 'REMOVE': return state.filter(({ id }) => id !== action.id) // this is buggy, but that's beside the point
default: throw new Error()
}
}
function App() {
const [todos, dispatch] = useReducer(todoReducer, [])
const newTodoRef = useRef<HTMLInputElement>(null)
const onAddTodo = useCallback(() => {
if (newTodoRef.current) {
dispatch({ type: "ADD", text: newTodoRef.current.value })
newTodoRef.current.value = ''
}
}, [])
return (
<div>
{todos.map(todo => (
<div key={todo.id}>
{todo.text}
<button onClick={() => dispatch({ type:"REMOVE", id: todo.id })}>Remove</button>
</div>
))}
<input type="text" ref={newTodoRef}/>
<button onClick={onAddTodo}>ADD</button>
</div>
)
}
export default App;
Why isn't the content of newTodoRef.current.value captured by useCallback just once when App first renders?
对顶级对象的引用,newTodoRef
,是以这种方式捕获的。效果很好的原因是 ref 是一个可变对象,并且在每次渲染时都是同一个对象。一旦 React 在页面上创建了 div 元素,它将改变 newTodoRef
,将其 .current
属性 更改为该元素。然后稍后,您访问 newTodoRef
,它仍然是同一个对象,并且您得到它是 .current
属性。 属性 在此期间发生了变化,但对象没有变化。
我不希望以下 React 应用程序正常工作,但它确实如此。我希望 useCallback 挂钩捕获并保留 ref 的初始值。我知道 ref 不能列在依赖项数组中,所以这可能是一个仅用于 refs 的特殊情况?
为什么 newTodoRef.current.value 的内容在 App 首次渲染时不被 useCallback 捕获一次?
import React, { useCallback, useReducer, useRef } from 'react';
type Todo = { id: number, text: string }
type ActionType = { type: 'ADD', text: string} | { type: 'REMOVE', id: number}
const todoReducer = (state: Todo[], action: ActionType) => {
switch(action.type) {
case 'ADD': return [ ...state, { id: state.length, text: action.text }]
case 'REMOVE': return state.filter(({ id }) => id !== action.id) // this is buggy, but that's beside the point
default: throw new Error()
}
}
function App() {
const [todos, dispatch] = useReducer(todoReducer, [])
const newTodoRef = useRef<HTMLInputElement>(null)
const onAddTodo = useCallback(() => {
if (newTodoRef.current) {
dispatch({ type: "ADD", text: newTodoRef.current.value })
newTodoRef.current.value = ''
}
}, [])
return (
<div>
{todos.map(todo => (
<div key={todo.id}>
{todo.text}
<button onClick={() => dispatch({ type:"REMOVE", id: todo.id })}>Remove</button>
</div>
))}
<input type="text" ref={newTodoRef}/>
<button onClick={onAddTodo}>ADD</button>
</div>
)
}
export default App;
Why isn't the content of newTodoRef.current.value captured by useCallback just once when App first renders?
对顶级对象的引用,newTodoRef
,是以这种方式捕获的。效果很好的原因是 ref 是一个可变对象,并且在每次渲染时都是同一个对象。一旦 React 在页面上创建了 div 元素,它将改变 newTodoRef
,将其 .current
属性 更改为该元素。然后稍后,您访问 newTodoRef
,它仍然是同一个对象,并且您得到它是 .current
属性。 属性 在此期间发生了变化,但对象没有变化。