Почему изменение значения на одном входе также приводит к изменению значения на другом входе? - PullRequest
0 голосов
/ 19 сентября 2019

Я пытаюсь учиться и экспериментировать с крючками React.Для небольшого тестового проекта я хочу обновить сетку календаря, когда пользователь меняет режим отображения или меняет дату.

Здесь Calendar.jsx.Государство хранится здесь.date и setDate передаются как реквизиты на CalendarDatePicker.

import React, {useState} from 'react';
import PropTypes from 'prop-types';
import CalendarDisplayMode from './CalendarDisplayMode';
import CalendarDatePicker from './CalendarDatePicker';
import CalendarGrid from './CalendarGrid';

const Calendar = props => {
    const [date, setDate] = useState(props.date);
    const [mode, setMode] = useState(props.mode);

    return (
        <div className="bg-light border border-dark rounded p-1">
            <CalendarDisplayMode mode={mode} setMode={setMode} />
            <CalendarDatePicker date={date} setDate={setDate} />
            <CalendarGrid displayDate={date} displayMode={mode} />
        </div>
    );
}

Calendar.propTypes = {
    date: PropTypes.instanceOf(Date).isRequired,
    mode: PropTypes.oneOf(['day', 'week', 'month', 'year']).isRequired
}

export default Calendar;

Здесь CalendarDatePicker.jsx.Когда любой из входов изменяется, вызывается setDate и передается новая дата.Это должно обновить состояние в Calendar.

import React from 'react';
import PropTypes from 'prop-types';

const CalendarDatePicker = ({date, setDate}) => {
    const year = date.getFullYear();
    const month = date.getMonth() + 1;
    const day = date.getDate();

    const handleYearChange = event => setDate(new Date(event.target.value, month, day));
    const handleMonthChange = event => setDate(new Date(year, event.target.value - 1, day));
    const handleDayChange = event => setDate(new Date(year, month, event.target.value));

    return (
        <div>
            <div className="form-group">
                <label htmlFor="display-year">Year</label>
                <input
                    type="number"
                    id="display-year"
                    name="display-year"
                    className="form-control form-control-sm"
                    min="1"
                    value={year}
                    onChange={handleYearChange} />
            </div>
            <div className="form-group">
                <label htmlFor="display-month">Month</label>
                <input
                    type="number"
                    id="display-month"
                    name="display-month"
                    className="form-control form-control-sm"
                    min="1"
                    max="12"
                    value={month}
                    onChange={handleMonthChange} />
            </div>
            <div className="form-group">
                <label htmlFor="display-day">Day</label>
                <input
                    type="number"
                    id="display-day"
                    name="display-day"
                    className="form-control form-control-sm"
                    min="1"
                    max="31"
                    value={day}
                    onChange={handleDayChange} />
            </div>
        </div>
    );
}

CalendarDatePicker.propTypes = {
    date: PropTypes.instanceOf(Date).isRequired,
    setDate: PropTypes.func.isRequired
}

export default CalendarDatePicker;

Но я наблюдаю странное поведение.Если я увеличиваю или уменьшаю число в поле года, поле месяца увеличивает его значение.Если я увеличу или уменьшу поле месяца, ни одно из других полей не изменит значения (как и ожидалось).Если я увеличиваю или уменьшаю число в поле дня, поле месяца увеличивает его значение.Если я увеличиваю или уменьшаю число в поле дня достаточно, поле месяца переворачивается (с 12 до 1), а поле года также увеличивает его значение.

Может кто-нибудь объяснить, что здесь может происходить и как это исправить?это?

Ответы [ 2 ]

1 голос
/ 19 сентября 2019

РЕДАКТИРОВАТЬ: обрабатывая это таким образом, вы также можете изменить общее количество дней в месяце и т. Д. Без необходимости жестко кодировать его до 31. Просто пример того, как этот дизайнпозволяет вам быть гибким.

Я лично не понимаю, почему вы передаете setDate дочернему компоненту ... Я не вижу смысла в этом или что вы выигрываете от этого..

По моему мнению, проблема связана с тем, как вы обрабатываете свой дизайн.

Каждый раз, когда что-то меняется, const year, const day, const month все запускается снова .. этогде вы должны использовать state. Просто передайте date в качестве реквизита, затем обработайте все изменения этой даты локально для компонента DatePicker ..., позволяя ребенку связаться с родителем и изменитьэто состояние мне кажется странным.

Примерно так я и поступил бы - это намного чище.

const { useState, useEffect } = React;
const { render } = ReactDOM;

const CalendarDatePicker = ({date, onDateChange}) => {
    const [year, setYear] = useState();
    const [month, setMonth] = useState();
    const [day, setDay] = useState();
    const [daysInMonth, setDaysInMonth] = useState();
  
    useEffect(() => {
      setYear(date.getFullYear());
      setMonth(date.getMonth() + 1);
      setDay(date.getDate());
    }, [date])
  
    useEffect(() => {
      let dim = getDaysInMonth(month, year);
      setDaysInMonth(dim);
    }, [month, year]);

    const handleYearChange = event => {
      let nd = new Date(event.target.value, month, day);
      setYear(nd.getFullYear());
      onDateChange(nd);
    }
    const handleMonthChange = event => {
      let nd = new Date(year, event.target.value - 1, day)
      setMonth(nd.getMonth() + 1);
      onDateChange(nd);
    }
    const handleDayChange = event => {
      let nd = new Date(year, month, event.target.value);
      setDay(nd.getDate());
      onDateChange(nd);
    }
    
    function getDaysInMonth(month, year) {
      return new Date(year, month, 0).getDate();
    }

    return (
        <div>
            <div className="form-group">
                <label htmlFor="display-year">Year</label>
                <input
                    type="number"
                    id="display-year"
                    name="display-year"
                    className="form-control form-control-sm"
                    min="1"
                    value={year}
                    onChange={handleYearChange} />
            </div>
            <div className="form-group">
                <label htmlFor="display-month">Month</label>
                <input
                    type="number"
                    id="display-month"
                    name="display-month"
                    className="form-control form-control-sm"
                    min="1"
                    max="12"
                    value={month}
                    onChange={handleMonthChange} />
            </div>
            <div className="form-group">
                <label htmlFor="display-day">Day</label>
                <input
                    type="number"
                    id="display-day"
                    name="display-day"
                    className="form-control form-control-sm"
                    min="1"
                    max={daysInMonth}
                    value={day}
                    onChange={handleDayChange} />
            </div>
        </div>
    );
}


const Calendar = props => {
    const handleDateChange = event => {
      console.log('You can change the `Calendar` during this event when the date changes...', event);
    }
    
    return (
        <div className="bg-light border border-dark rounded p-1">
            <CalendarDatePicker date={props.date} onDateChange={handleDateChange} />
        </div>
    );
}

render(<Calendar date={new Date(Date.now())} />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>
1 голос
/ 19 сентября 2019
    const handleYearChange = event => setDate(new Date(event.target.value, month, day));
    const handleMonthChange = event => setDate(new Date(year, event.target.value - 1, day));
    const handleDayChange = event => setDate(new Date(year, month, event.target.value));

В handleYearChange и handleDayChange вы передаете month, что на самом деле date.getMonth() + 1 - вам нужно сделать month - 1.

, поэтому ваш месяц увеличивается на 1, когда годили день меняется.

...