问题
我有一个“日历”组件,当单击一天时,它会在其父级(属性)中调用一个函数。整天被点击的事情并不重要,因为我已经剥离了很多代码以试图找出问题所在。
在父级中,我让其运行一个控制台状态状态的函数。但是,它使用状态的初始值,而不是设置的值。但是,使用日历下方的我设置的按钮(调用相同的功能)可以得到正确的数据。因此,我知道数据是从数据库中加载和设置的。
预期结果
在日历上单击调用console.log函数的一天,应显示页面加载时设置的状态值。
实际结果
console.log状态使用的是最初创建时的值,而不是设置的值。
我所做的事情
最初,BookPage.js(“父”文件)具有更多代码,但是我将其剥离了下来,直到发现问题与我制作的日历组件有关。为确保该问题与我的数据库无关,我在日历下方添加了按钮,该按钮调用了与日历相同的功能。单击该按钮将显示正确的值。
这是我的页面
import { Colors, Styles } from "./GlobalStyles";
import {
Button,
Grid,
TextField,
Box,
Tooltip,
SvgIcon,
Slider,
} from "@material-ui/core";
import {
English,
French,
Spanish,
Tagalog,
Chinese,
Korean,
Arabic,
Hindi,
} from "../Strings";
import moment from "moment";
import Calender from "./components/calender";
const BookPage = (props) => {
const initialState = {
expert: null,
availability: [
[1, 24],
[1, 24],
[1, 24],
[1, 24],
[1, 24],
[1, 24],
[1, 24],
],
};
const reducer = (state, newState) => ({ ...state, ...newState });
const [state, setState] = useReducer(reducer, initialState);
useEffect(() => {
LoadExpertData();
}, []);
// Loads the expert's data
const LoadExpertData = async () => {
await props.firestore
.collection("expertData")
.where("userID", "==", props.bookID)
.get()
.then((loadedData) => {
setState({
availability: [
[
loadedData.docs[0].data().availability.availability.sun[0],
loadedData.docs[0].data().availability.availability.sun[1],
],
[
loadedData.docs[0].data().availability.availability.mon[0],
loadedData.docs[0].data().availability.availability.mon[1],
],
[
loadedData.docs[0].data().availability.availability.tue[0],
loadedData.docs[0].data().availability.availability.tue[1],
],
[
loadedData.docs[0].data().availability.availability.wed[0],
loadedData.docs[0].data().availability.availability.wed[1],
],
[
loadedData.docs[0].data().availability.availability.thu[0],
loadedData.docs[0].data().availability.availability.thu[1],
],
[
loadedData.docs[0].data().availability.availability.fri[0],
loadedData.docs[0].data().availability.availability.fri[1],
],
[
loadedData.docs[0].data().availability.availability.sat[0],
loadedData.docs[0].data().availability.availability.sat[1],
],
],
});
});
};
const alertData = () => {
console.log(state.availability);
};
return (
<div>
<Calender language={props.language} ReturnDay={(d) => alertData()} />
<Button onClick={() => alertData()}>BUTTON</Button>
</div>
);
};
export default BookPage;
这是日历
import React, { useReducer, useEffect } from "react";
import { Colors, Styles } from "../GlobalStyles";
import {
Button,
Grid,
TextField,
Box,
Tooltip,
SvgIcon,
Select,
MenuItem,
} from "@material-ui/core";
import moment from "moment";
import { English, French, Spanish } from "../../Strings";
const Calender = (props) => {
const initialState = {
dateObject: moment(),
weekdayshort: moment.weekdaysShort(),
blankDays: [],
yearLimit: [2020, 2021, 2022, 2023],
month: 0,
year: 2020,
};
const reducer = (state, newState) => ({ ...state, ...newState });
const [state, setState] = useReducer(reducer, initialState);
useEffect(() => {
GenerateCalender(null, null);
}, []);
// Finds the first day of the month
const GenerateCalender = (m, y) => {
if (m !== null && y !== null) {
state.dateObject.month(m);
state.dateObject.year(y);
} else {
setState({
month: state.dateObject.month(),
year: state.dateObject.year(),
});
}
var firstDay = moment(state.dateObject).startOf("month").format("d");
// Empty days
var emptyDay = [];
for (let i = 0; i < firstDay; i++) {
emptyDay.push(<td style={LocalStyles.calSlot}>{""}</td>);
}
// Actual Days
let actualDays = [];
for (let i = 1; i <= state.dateObject.daysInMonth(); i++) {
actualDays.push(
<td
key={i}
style={LocalStyles.clickableDay}
onClick={() =>
props.ReturnDay({
month: state.dateObject.month(),
day: i,
year: state.dateObject.year(),
})
}
>
{i}
</td>
);
}
var days = [...emptyDay, ...actualDays];
let rows = [];
let cells = [];
days.forEach((row, i) => {
if (i % 7 !== 0) {
cells.push(row);
} else {
rows.push(cells);
cells = [];
cells.push(row);
}
if (i === days.length - 1) {
rows.push(cells);
}
});
setState({
calender: rows.map((d, i) => {
return <tr>{d}</tr>;
}),
});
};
const ChangeYear = (year) => {
GenerateCalender(state.month, year);
setState({ year: year });
};
const ChangeMonth = (month) => {
GenerateCalender(month, state.year);
setState({ month: month });
};
return (
<div>
<Select
value={state.month}
onChange={(e) => {
ChangeMonth(e.target.value);
}}
style={{ width: 150 }}
>
{props.language.Calender.Months.map((m, v) => (
<MenuItem value={v}>{m}</MenuItem>
))}
</Select>
<Select
value={state.year}
onChange={(e) => {
ChangeYear(e.target.value);
}}
style={{ width: 150 }}
>
{state.yearLimit.map((y) => (
<MenuItem value={y}>{y}</MenuItem>
))}
</Select>
<p />
{props.language.Calender.Months[state.dateObject.month()]}
{state.dateObject.year()}
<table>
<thead>
<tr>
<td style={LocalStyles.calSlot}>
{props.language.Calender.DaysShort[0]}
</td>
<td style={LocalStyles.calSlot}>
{props.language.Calender.DaysShort[1]}
</td>
<td style={LocalStyles.calSlot}>
{props.language.Calender.DaysShort[2]}
</td>
<td style={LocalStyles.calSlot}>
{props.language.Calender.DaysShort[3]}
</td>
<td style={LocalStyles.calSlot}>
{props.language.Calender.DaysShort[4]}
</td>
<td style={LocalStyles.calSlot}>
{props.language.Calender.DaysShort[5]}
</td>
<td style={LocalStyles.calSlot}>
{props.language.Calender.DaysShort[6]}
</td>
</tr>
</thead>
<tbody>{state.calender}</tbody>
</table>
</div>
);
};
const LocalStyles = {
calSlot: {
width: 60,
margin: 5,
},
clickableDay: {
width: 60,
margin: 5,
cursor: "pointer",
},
};
export default Calender;
在这里,我有页面一部分的屏幕截图。我有日历和一个按钮。图像右侧是这两种情况的结果。最上面的是,如果单击日历上的某天,则会导致使用该州的初始值。底部是单击该按钮时,将导致加载正确的值。两者都调用与console.log状态相同的功能。
答案 0 :(得分:0)
我觉得整个组件的生命周期中有些根本不了解的东西,但是您可以尝试useCallback
:
const alertData = React.useCallback(
() => console.log(state.availability),
[state.availability]
);