我的状态使用的是初始值,而不是从组件调用页面加载时设置的初始值

时间:2020-07-01 00:01:17

标签: javascript reactjs

问题

我有一个“日历”组件,当单击一天时,它会在其父级(属性)中调用一个函数。整天被点击的事情并不重要,因为我已经剥离了很多代码以试图找出问题所在。

在父级中,我让其运行一个控制台状态状态的函数。但是,它使用状态的初始值,而不是设置的值。但是,使用日历下方的我设置的按钮(调用相同的功能)可以得到正确的数据。因此,我知道数据是从数据库中加载和设置的。

预期结果

在日历上单击调用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状态相同的功能。

Image of the page and the results


1 个答案:

答案 0 :(得分:0)

我觉得整个组件的生命周期中有些根本不了解的东西,但是您可以尝试useCallback

const alertData = React.useCallback(
  () => console.log(state.availability), 
  [state.availability]
);