在 React 中使用 useState 挂钩为多个设置状态渲染一次
Render Once for Multiple set States using useState hook in React
有没有办法在更新多个状态后刷新/渲染一次功能组件?
例如:
const [first, setFirst] = useState(false);
const [second, setSecond] = useState(false);
调用时...
...
setFirst(true);
setSecond(true);
...然后组件会刷新两次。是否可以同时设置并刷新(或渲染)一次?
我没有看到它渲染了两次。它只渲染一次,因为两个设置状态一起 batched。
function App() {
const [first, setFirst] = React.useState(false);
const [second, setSecond] = React.useState(false);
const counter = React.useRef(1)
console.log('rendering: ', counter.current++)
return (
<button onClick={() => {
setFirst(p => !p)
setSecond(p => !p)
}}>{first?'t1':'f1'}, {second?'t2':'f2'}</button>)
}
ReactDOM.render(<App />, document.getElementById('mydiv'))
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<body>
<div id="mydiv"></div>
</body>
也许,由于使用 StrictMode. StrictMode
will intentionally double invoke "render" and some other lifecycle methods to detect side-effects.
,您看到它渲染了两次
有关演示,请参阅 Why is React Component render counter getting incremented by 2?。
更新:
我认为您正在寻找@EvrenK 中提到的解决方案,即 合并您的状态变量.
通常,在大多数情况下,您不必太担心重新渲染,除非它成为一个明显的问题。如果当它变得明显 问题/延迟 时,您可以使用 Reat.memo
避免因 props
中的更改而导致的 渲染 。
没办法,可以避免states
.
变化引起的渲染
但是,有一种 hacky 方法可以更好地控制渲染:将所有(导致问题的少数)数据从状态移动到 ref
/ useRef
并创建 一个状态数据 以触发最终渲染。
示例:
const data1 = useRef()
const data2 = useRef()
const data3 = useRef()
const [renderD1D2D3, setRenderD1D2D3] = useState(false)
function handleChange1(newValue) {
data1.current = newValue // Won't trigger render
}
function handleChange2(newValue) {
data2.current = newValue // Won't trigger render
}
function handleChange3(newValue) {
data3.current = newValue // Won't trigger render
}
function allGoodLetsRenderNow() {
setRenderD1D2D3(prev => !prev) // Would trigger render
}
return (
<>
<div>{data1.current}</div>
<div>{data2.current}</div>
<div>{data3.current}</div>
</>
)
您可以将您的状态用作一个对象并将它们设置为一个而不是单独的状态,例如
const [exampleState, setExampleState] = useState(
{fields: {
fieldOne: false,
fieldTwo: false
}
})
可以这样设置
setExampleState({...exampleState, fields: {
fieldOne: true,
fieldTwo: true
},
})
有没有办法在更新多个状态后刷新/渲染一次功能组件?
例如:
const [first, setFirst] = useState(false);
const [second, setSecond] = useState(false);
调用时...
...
setFirst(true);
setSecond(true);
...然后组件会刷新两次。是否可以同时设置并刷新(或渲染)一次?
我没有看到它渲染了两次。它只渲染一次,因为两个设置状态一起 batched。
function App() {
const [first, setFirst] = React.useState(false);
const [second, setSecond] = React.useState(false);
const counter = React.useRef(1)
console.log('rendering: ', counter.current++)
return (
<button onClick={() => {
setFirst(p => !p)
setSecond(p => !p)
}}>{first?'t1':'f1'}, {second?'t2':'f2'}</button>)
}
ReactDOM.render(<App />, document.getElementById('mydiv'))
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<body>
<div id="mydiv"></div>
</body>
也许,由于使用 StrictMode. StrictMode
will intentionally double invoke "render" and some other lifecycle methods to detect side-effects.
有关演示,请参阅 Why is React Component render counter getting incremented by 2?。
更新:
我认为您正在寻找@EvrenK
通常,在大多数情况下,您不必太担心重新渲染,除非它成为一个明显的问题。如果当它变得明显 问题/延迟 时,您可以使用 Reat.memo
避免因 props
中的更改而导致的 渲染 。
没办法,可以避免states
.
但是,有一种 hacky 方法可以更好地控制渲染:将所有(导致问题的少数)数据从状态移动到 ref
/ useRef
并创建 一个状态数据 以触发最终渲染。
示例:
const data1 = useRef()
const data2 = useRef()
const data3 = useRef()
const [renderD1D2D3, setRenderD1D2D3] = useState(false)
function handleChange1(newValue) {
data1.current = newValue // Won't trigger render
}
function handleChange2(newValue) {
data2.current = newValue // Won't trigger render
}
function handleChange3(newValue) {
data3.current = newValue // Won't trigger render
}
function allGoodLetsRenderNow() {
setRenderD1D2D3(prev => !prev) // Would trigger render
}
return (
<>
<div>{data1.current}</div>
<div>{data2.current}</div>
<div>{data3.current}</div>
</>
)
您可以将您的状态用作一个对象并将它们设置为一个而不是单独的状态,例如
const [exampleState, setExampleState] = useState(
{fields: {
fieldOne: false,
fieldTwo: false
}
})
可以这样设置
setExampleState({...exampleState, fields: {
fieldOne: true,
fieldTwo: true
},
})