setter 方法会在 React 中触发 DOM 重新渲染吗?
Do setter methods trigger a DOM rerender in React?
我正在通过做一个基本的日历应用程序来学习 React,这在很大程度上依赖于使用 Date() 对象。我正在尝试显示选定的月份,通过单击几个字体很棒的箭头图标可以更改它。
使用上下文 API 和 useState,我正在使用“setDateObject”回调更新日期,它使用日期对象的 setter 函数“setMonth()”。
只是做一些控制台日志显示日期已成功更新状态,但
标记中显示的日期未被重新呈现。我尝试用硬类型对象切换日期对象,并在“incrementMonth”方法中手动递增月份,这确实会触发重新渲染。
所以要么我误解了什么,要么使用 setter 函数更新日期对象并没有触发重新渲染。有人有过这方面的经验吗?
提前致谢!
对象
import React, { useContext } from "react"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
// Styling
import style from "../styles/Calendar.css"
// Assets
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons"
import { faArrowRight } from "@fortawesome/free-solid-svg-icons"
// Contexts
import { DateContext } from "./context/DateContext.js"
const Calendar = () => {
const [dateObj, setDateObj] = useContext(DateContext)
const monthArray = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
const incrementMonth = () => {
setDateObj(prevDate => {
let newDate = prevDate
newDate.setMonth(prevDate.getMonth() + 1)
return newDate
})
}
const decrementMonth = () => {
setDateObj(prevDate => {
let newDate = prevDate
newDate.setMonth(prevDate.getMonth() - 1)
return newDate
})
}
return(
<div style={style} className="CalendarWrapper">
<div className="MonthSelector">
<FontAwesomeIcon icon={faArrowLeft} onClick={decrementMonth} className="hoverArrow"/>
<p>{ `${ monthArray[dateObj.getMonth()] } ${ dateObj.getFullYear() }` }</p>
<FontAwesomeIcon icon={faArrowRight} onClick={incrementMonth} className="hoverArrow"/>
</div>
</div>
)
}
export default Calendar
上下文
import React, { useState, createContext } from "react"
export const DateContext = createContext(null)
export const DateProvider = props => {
const [dateObj, setDateObj] = useState(new Date())
return(
<DateContext.Provider value={[dateObj, setDateObj]}>
{props.children}
</DateContext.Provider>
)
}
React 试图在 re-rendering 上变得聪明。如果新状态和旧状态引用相同的值,it doesn't re-render.
您实际上是在用相同的日期对象调用 setDateObj
,即使您已经更改了它的内部数据。换句话说,如果newDate === prevDate
,则不会re-render。您可以通过这样复制日期来避免这种情况:
const newDate = new Date(prevDate);
我正在通过做一个基本的日历应用程序来学习 React,这在很大程度上依赖于使用 Date() 对象。我正在尝试显示选定的月份,通过单击几个字体很棒的箭头图标可以更改它。
使用上下文 API 和 useState,我正在使用“setDateObject”回调更新日期,它使用日期对象的 setter 函数“setMonth()”。
只是做一些控制台日志显示日期已成功更新状态,但
标记中显示的日期未被重新呈现。我尝试用硬类型对象切换日期对象,并在“incrementMonth”方法中手动递增月份,这确实会触发重新渲染。
所以要么我误解了什么,要么使用 setter 函数更新日期对象并没有触发重新渲染。有人有过这方面的经验吗?
提前致谢!
对象
import React, { useContext } from "react"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
// Styling
import style from "../styles/Calendar.css"
// Assets
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons"
import { faArrowRight } from "@fortawesome/free-solid-svg-icons"
// Contexts
import { DateContext } from "./context/DateContext.js"
const Calendar = () => {
const [dateObj, setDateObj] = useContext(DateContext)
const monthArray = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
const incrementMonth = () => {
setDateObj(prevDate => {
let newDate = prevDate
newDate.setMonth(prevDate.getMonth() + 1)
return newDate
})
}
const decrementMonth = () => {
setDateObj(prevDate => {
let newDate = prevDate
newDate.setMonth(prevDate.getMonth() - 1)
return newDate
})
}
return(
<div style={style} className="CalendarWrapper">
<div className="MonthSelector">
<FontAwesomeIcon icon={faArrowLeft} onClick={decrementMonth} className="hoverArrow"/>
<p>{ `${ monthArray[dateObj.getMonth()] } ${ dateObj.getFullYear() }` }</p>
<FontAwesomeIcon icon={faArrowRight} onClick={incrementMonth} className="hoverArrow"/>
</div>
</div>
)
}
export default Calendar
上下文
import React, { useState, createContext } from "react"
export const DateContext = createContext(null)
export const DateProvider = props => {
const [dateObj, setDateObj] = useState(new Date())
return(
<DateContext.Provider value={[dateObj, setDateObj]}>
{props.children}
</DateContext.Provider>
)
}
React 试图在 re-rendering 上变得聪明。如果新状态和旧状态引用相同的值,it doesn't re-render.
您实际上是在用相同的日期对象调用 setDateObj
,即使您已经更改了它的内部数据。换句话说,如果newDate === prevDate
,则不会re-render。您可以通过这样复制日期来避免这种情况:
const newDate = new Date(prevDate);