如何仅使用 1 个带有钩子的处理程序来处理多个输入更改

Wok*_*ers 1 javascript reactjs react-hooks

我有几个状态,我只想为所有状态编写 1 个处理程序。更改时,只有 1 个处理程序会触发并仅在状态发生更改时更改状态。

我有这样的基于类的组件的解决方案

handleChange (evt) {
    this.setState({ [evt.target.name]: evt.target.value });
}
Run Code Online (Sandbox Code Playgroud)

但是当我使用基于函数的组件时,我不知道如何使用。

export default function DateBar(props)
{
    let date = new Date();
    let i = 1;
    const days = Array.from({length: new Date(date.getYear(), date.getMonth() + 1, 0).getDate()}).map(() => <option key = {uuidv4()} value={i}>{i++}</option>);

    const monthOpts = props.months.map(month => <option key = {uuidv4()} value={month} name = {month} id = {month}>{month}</option>);
    const yearsOpts = props.years.map(year => <option key = {uuidv4()} value ={year} name = {year} id = {year}>{year}</option>);


    // states
    const [today, setToday] = useState("");
    const [thisMonth, setThisMonth] = useState("");
    const [year, setYear] = useState("");

    useEffect(() =>
    { 
        setToday(date.getDate());
        setThisMonth(props.months[date.getMonth()]);
        setYear(date.getYear());
    }, []);

    const handleChange = () => 
{
    // for example, if day is changed, i want to call setToday() somehow..
}

    return(
        <div className="DateBarRoot">
                <FormControl className="formControl input" variant="outlined">
                    <InputLabel htmlFor="today">Day</InputLabel>
                    <Select
                    native
                    value={today}
                    onChange={handleChange}
                    label = 'day'
                    inputProps={{
                        name: 'today',
                        id: 'today',
                    }}
                    >
                        {days}
                    </Select>
                </FormControl>
                <FormControl className="formControl input" variant="outlined">
                    <InputLabel htmlFor="month">Month</InputLabel>
                    <Select
                    native
                    value={thisMonth}
                    onChange={handleChange}
                    label = 'month'
                    inputProps={{
                        name: 'thisMonth',
                        id: 'thisMonth',
                    }}
                    >
                        {monthOpts}
                    </Select>
                </FormControl>
                <FormControl variant="outlined" className="formControl input">
                    <InputLabel htmlFor="year">Year</InputLabel>
                    <Select
                    native
                    className="select"
                    value={year}
                    onChange={handleChange}
                    label = 'year'
                    inputProps={{
                        name: 'year',
                        id: 'year',
                    }}
                    >
                        {yearsOpts}
                    </Select>
                </FormControl>                
            </div>
    )
}

Run Code Online (Sandbox Code Playgroud)

预先非常感谢。

T.J*_*der 5

您可以有一个保存这些值的状态项。事实上,useState文档已经涵盖了这一点:

笔记

setState与类组件中的方法不同,useState它不会自动合并更新对象。您可以通过将函数更新器形式与对象扩展语法相结合来复制此行为:

const [state, setState] = useState({});
setState(prevState => {
  // Object.assign would also work
  return {...prevState, ...updatedValues};
});
Run Code Online (Sandbox Code Playgroud)

另一个选项是useReducer,它更适合管理包含多个子值的状态对象。

在你的情况下,它可能是:

const [values, setValues] = useState({}); // Or maybe a Map
// ...
const handleChange = (event) => {
    setValues(values => {
        return {...values, [event.target.name]: event.target.value};
    });
};
Run Code Online (Sandbox Code Playgroud)

或者进行一些解构:

const [values, setValues] = useState({}); // Or maybe a Map
// ...
const handleChange = ({target: {name, value}}) => {
    setValues(values => {
        return {...values, [name]: value};
    });
};
Run Code Online (Sandbox Code Playgroud)

或者,正如上面所说,您可以在事件目标名称上使用useReducerand ,可能是 a 。switch