我正在按照本
如何停止將date變數重置回1每一行的末尾?
uj5u.com熱心網友回復:
簡單的答案,將您的列印提取到另一個函式中并使用組件的 return 陳述句呼叫它。另請注意,您的列印陳述句為 O(n^2),因此重新渲染是一項昂貴的操作。
代碼:
import { useState, useRef, useMemo } from 'react'
import type { NextPage } from 'next'
import Head from 'next/head'
import styles from '../styles/Home.module.scss'
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
// console.log('render')
const Home: NextPage = () => {
const today = new Date()
const [currentMonth, setCurrentMonth] = useState(today.getMonth())
const [currentYear, setCurrentYear] = useState(today.getFullYear())
const calendarBodyRef = useRef<HTMLDivElement>(null)
const rows = 6
const cells = 7
const firstDay = (new Date(currentYear, currentMonth)).getDay()
// check how many days in a month code from https://dzone.com/articles/determining-number-days-month
const daysInMonth = (iMonth: number, iYear: number) => {
return 32 - new Date(iYear, iMonth, 32).getDate()
}
const renderCalendar = () => {
let date = 1;
return [...Array(rows).keys()].map((row) => {
return (
<div key={row} className={styles.row}>
{[...Array(cells).keys()].map((cell) => {
if (row === 0 && cell < firstDay) {
return (
<div key={cell} className={styles.cell}></div>
)
} else if (date > daysInMonth(currentMonth, currentYear)) {
return
} else {
const cellText = String(date)
date
return (
<div key={cell} className={styles.cell}>{cellText}</div>
)
}
})}
</div>
)
})}
}
return (
<>
<Head>
<title>Calendar Budget App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div className={styles.calendarWrap}>
<h2 className={styles.monthTitle}>{months[currentMonth]} {currentYear}</h2>
<div className={styles.daysWrap}>
<span>Sun</span>
<span>Mon</span>
<span>Tue</span>
<span>Wed</span>
<span>Thu</span>
<span>Fri</span>
<span>Sat</span>
</div>
<div ref={calendarBodyRef} className={styles.calendarBody}>
{renderCalendar()}
</div>
</div>
</>
)
}
export default Home
uj5u.com熱心網友回復:
我對接受的答案及其討論不太滿意,所以這里有一個相當長的答案來提供一些額外的背景關系。我希望它可能會有所幫助,如果沒有,那我想那就是運氣不好了。
從邏輯上講,您的問題是您在[...Array(rows).keys()].map回呼 ( let date = 1) 中初始化了變數。因此,將初始化移出回圈將解決此問題。
從語法上講,您不能只是將它移到map呼叫之外,因為您使用的是 JSX,它只是為呼叫提供語法糖React.createElement(component, props, ...children)。雖然您的map呼叫回傳一個 JSX 元素陣列,因此回傳了一個有效的引數children,但在其位置使用的變數宣告let將導致語法錯誤。
如已接受的答案所示,將渲染邏輯提取到單獨的函式中以便在回圈之前移動初始化可以解決此問題。然而,重要的是,它不會提取相同的邏輯,而是使您能夠稍微更改您的邏輯(通過將初始化移到回圈之外)。此外,新功能并非絕對必要,其他語法技巧可以讓您實作相同的目標,例如:
<div key={row} className={styles.row}>
{[0].map((e) => {
let date = 1;
return [...Array(cells).keys()].map((cell) => {
if (row === 0 && cell < firstDay) {
return <div key={cell} className={styles.cell}></div>;
} else if (date > daysInMonth(currentMonth, currentYear)) {
return;
} else {
const cellText = String(date);
date ;
return (
<div key={cell} className={styles.cell}>
{cellText}
</div>
);
}
});
})}
</div>;
無需花費太多時間分析您的邏輯,我相信您甚至可以將初始化移動到組件的頂部,這樣就可以解決問題。
您最終遇到的情況是具有副作用的回呼函式之一(在date回呼外部宣告的內容從回呼內部更改),這通常會對代碼的可讀性和可維護性產生負面影響。JSX 與宣告性方法和函式式編程(如您的使用map所示)配合得很好。下面是一個示例,說明如何通過計算沒有副作用的天數來實作目標。簡而言之,可以根據周指數、日指數(均由 提供map)、當月第一天指數計算出相應日
const {
useState
} = React;
const App = () => {
const today = new Date();
const [currentMonth, setCurrentMonth] = useState(today.getMonth());
const currentYear = today.getFullYear();
const months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
const weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const daysInMonth = (iMonth, iYear) => {
return 32 - new Date(iYear, iMonth, 32).getDate();
};
const calculateDay = (weekIndex, dayIndex, offset) =>
7 * (weekIndex 1) - (6 - dayIndex) - offset;
const renderCalendar = () => {
const totalDays = daysInMonth(currentMonth, currentYear);
const firstDayInMonth = new Date(currentYear, currentMonth).getDay();
const totalWeeks = Math.ceil((firstDayInMonth totalDays) / 7);
return (
<div className="table">
<div className="row">
{weekDays.map((e) => (
<div className="column" key={`col${e}`}>
{e}
</div>
))}
</div>
{[...Array(totalWeeks)].map((w, wIx) => {
return (
<div className="row">
{weekDays.map((d, dIx) => (
<div className="column">
{(wIx === 0 && dIx < firstDayInMonth) ||
calculateDay(wIx, dIx, firstDayInMonth) > totalDays
? ""
: calculateDay(wIx, dIx, firstDayInMonth)}
</div>
))}
</div>
);
})}
</div>
);
};
return (
<div>
<h1>Calendar Budget App</h1>
<div>
<select
value={currentMonth}
onChange={(e) => setCurrentMonth(e.target.value)}
>
{months.map((m, i) => (
<option value={i}>{m}</option>
))}
</select>
<h2>
{months[currentMonth]} {currentYear}
</h2>
{renderCalendar()}
</div>
</div>
);
};
// Render it
ReactDOM.render( <App / > ,
document.getElementById("root")
);
.App {
font-family: sans-serif;
text-align: center;
}
.table {
margin: 48px 0;
box-shadow: 0 5px 10px -2px #cfcfcf;
font-family: Arial;
display: table;
width: 100%;
}
.row {
display: table-row;
min-height: 48px;
border-bottom: 1px solid #f1f1f1;
}
.column {
display: table-cell;
border: 1px solid #f1f1f1;
vertical-align: middle;
padding: 10px 0;
}
.row:first-child {
font-weight: bold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
uj5u.com熱心網友回復:
我喜歡 michmich112 的回答,但不幸的是我不能對此發表評論(缺乏聲譽)
但是您可以通過添加 useMemo 來改善渲染時間
import { useState, useRef, useMemo } from 'react'
import type { NextPage } from 'next'
import Head from 'next/head'
import styles from '../styles/Home.module.scss'
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
// console.log('render')
const Home: NextPage = () => {
const today = new Date()
const [currentMonth, setCurrentMonth] = useState(today.getMonth())
const [currentYear, setCurrentYear] = useState(today.getFullYear())
const calendarBodyRef = useRef<HTMLDivElement>(null)
const rows = 6
const cells = 7
const firstDay = (new Date(currentYear, currentMonth)).getDay()
// check how many days in a month code from https://dzone.com/articles/determining-number-days-month
const daysInMonth = (iMonth: number, iYear: number) => {
return 32 - new Date(iYear, iMonth, 32).getDate()
}
const renderCalendar = useMemo(() => {
let date = 1;
return [...Array(rows).keys()].map((row) => {
return (
<div key={row} className={styles.row}>
{[...Array(cells).keys()].map((cell) => {
if (row === 0 && cell < firstDay) {
return (
<div key={cell} className={styles.cell}></div>
)
} else if (date > daysInMonth(currentMonth, currentYear)) {
return
} else {
const cellText = String(date)
date
return (
<div key={cell} className={styles.cell}>{cellText}</div>
)
}
})}
</div>
)
})}
}, [currentMonth, currentYear])
return (
<>
<Head>
<title>Calendar Budget App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div className={styles.calendarWrap}>
<h2 className={styles.monthTitle}>{months[currentMonth]} {currentYear}</h2>
<div className={styles.daysWrap}>
<span>Sun</span>
<span>Mon</span>
<span>Tue</span>
<span>Wed</span>
<span>Thu</span>
<span>Fri</span>
<span>Sat</span>
</div>
<div ref={calendarBodyRef} className={styles.calendarBody}>
{renderCalendar()}
</div>
</div>
</>
)
}
export default Home
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/468677.html
標籤:javascript 反应 打字稿 反应钩子 下一个.js
上一篇:在我的Typescript專案中匯入JS函式時出現問題
下一篇:訪問函式型別中的引數型別
