代码之家  ›  专栏  ›  技术社区  ›  J. Owens

为什么更改一个输入中的值也会更改另一个输入中的值?

  •  0
  • J. Owens  · 技术社区  · 6 年前

    我在努力学习和试验反作用钩子。对于一个小型测试项目,我想在用户更改显示模式或更改日期时更新日历网格。

    这里是 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 . 当任何输入改变时 设置当前日期 被调用并传递了新日期。这将更新中的状态 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;
    

    但我在观察奇怪的行为。如果我在“年”字段中增加或减少数字,则“月”字段将增加其值。如果我增加或减少月份字段,其他字段都不会更改值(如预期)。如果我增加或减少“日”字段中的数字,则“月”字段将增加其值。如果我在day字段中增加或减少的数字足够多,那么month字段将滚动(从12到1),year字段也将增加其值。

    有人能解释一下这里可能发生的事情以及如何解决吗?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Yurui Zhang    6 年前
        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。

        2
  •  1
  •   Matt Oestreich    6 年前

    编辑: 这样处理,你也可以在一个月内更改总天数,等等。不用硬编码到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>