用typescript为MuiPickersUtilsProvider组件创建一个react容器组件



我有一个负责日期时间选择器的组件。我希望另一个父组件调用这个子日期选择器组件,这样我就可以有一个"包装器/容器"组件。还有一个是数据选取器。此外,我没有成功地在typescript上这样做.

这是我的代码沙盒:https://codesandbox.io/s/date-picker-ubosl?file=/src/App.tsx

这是我的代码,函数handleChangeDateType在结束时执行console.log(),结果应该传递给父组件。

import React, { useState } from "react";
import { DatePicker, MuiPickersUtilsProvider } from "@material-ui/pickers";
import ReactSelect, { ValueType } from "react-select";
import DateFnsUtils from "@date-io/date-fns";
export enum DateValueEnum {
Today = "TODAY",
Yesterday = "YESTERDAY",
Custom = "CUSTOM"
}
type OptionType = {
key: string;
label: string;
};
const options: OptionType[] = [
{ key: DateValueEnum.Today, label: "Today" },
{ key: DateValueEnum.Yesterday, label: "Yesterday" },
{ key: DateValueEnum.Custom, label: "Custom" }
];
export default function App() {
const [selectedDate, setSelectedDate] = React.useState<Date | null>(
new Date()
);
const [selectedOption, setSelectedOption] = useState<ValueType<OptionType>>();
const handleChangeDateType = (value: string) => {
let startDate: Date | undefined = undefined;
let endDate: Date | undefined = undefined;
const startToday = new Date();
switch (value) {
case DateValueEnum.Today: {
startDate = startToday;
endDate = new Date(startDate.getTime());
break;
}
case DateValueEnum.Yesterday: {
startDate = new Date(startToday.getTime());
startDate.setDate(startDate.getDate() - 1);
endDate = new Date(startDate.getTime());
break;
}
default: /**  nothing */
}
console.log(startDate);
console.log(endDate);
};
const handleChange = (option: ValueType<OptionType>) => {
setSelectedOption(option.key);
handleChangeDateType(option.key);
};
return (
<div className="App">
<div>
<ReactSelect
value={selectedOption as ValueType<OptionType>}
onChange={(option) => handleChange(option)}
isMulti={false}
options={options}
/>
{selectedOption === DateValueEnum.Custom ? (
<div style={{ display: "flex" }}>
<div style={{ width: "50%", float: "left", paddingRight: "5px" }}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<DatePicker
fullWidth
margin="normal"
required={true}
error={false}
invalidLabel={"Several values..."}
value={selectedDate}
onChange={(newDate) => setSelectedDate(newDate)}
format="MM/dd/yyyy"
/>
</MuiPickersUtilsProvider>
</div>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<DatePicker
fullWidth
margin="normal"
required={true}
error={false}
invalidLabel={"Several values..."}
value={selectedDate}
onChange={(newDate) => setSelectedDate(newDate)}
format="MM/dd/yyyy"
/>
</MuiPickersUtilsProvider>
</div>
) : null}
</div>
</div>
);
}

编辑:要回答最初的问题,我要做的是将状态从DateComponent中提取出来,并将它们放在父组件中,这样您就可以将日期和onChange函数从父组件传递到日期组件。

// App.tsx
import React from "react";
import { MuiPickersUtilsProvider } from "@material-ui/pickers";
import DateFnsUtils from "@date-io/date-fns";
import DateComponent from "./DateComponent";
export type IDates = {
startDate: Date | null;
endDate: Date | null;
};
export type IDatesKeys = keyof IDates;
const formatDate = (date: Date) => date.toLocaleString();
export default function App() {
const [dates, setDates] = React.useState<IDates>({
startDate: null,
endDate: null
});
const onChangeDate = (dates: IDates) => {
setDates(dates);
};
// Remember to wrap everything with the MuiPickersUtilsProvider
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<div className="App">
<DateComponent dates={dates} onChange={onChangeDate} />
{dates.startDate && <p>Start Date: {formatDate(dates.startDate)}</p>}
{dates.endDate && <p>End Date: {formatDate(dates.endDate)}</p>}
</div>
</MuiPickersUtilsProvider>
);
}
在你的DateComponent中,你需要这样做:
// DateComponent.tsx
import React from "react";
import { DatePicker } from "@material-ui/pickers";
import ReactSelect, { ValueType } from "react-select";
import { IDates, IDatesKeys } from "./App";
type IDateComponent = {
dates: IDates;
onChange: (dates: IDates) => void;
};
export enum DateValueEnum {
Today = "TODAY",
Yesterday = "YESTERDAY",
Custom = "CUSTOM"
}
type OptionType = {
key: DateValueEnum;
label: string;
};
const options: OptionType[] = [
{ key: DateValueEnum.Today, label: "Today" },
{ key: DateValueEnum.Yesterday, label: "Yesterday" },
{ key: DateValueEnum.Custom, label: "Custom" }
];
export default function DateComponent({ dates, onChange }: IDateComponent) {
const [selectedOption, setSelectedOption] = React.useState<
ValueType<OptionType, false>
>(null);
const handleChangeDateType = (value: DateValueEnum) => {
const today = new Date();
let startDate = new Date();
let endDate = new Date();
switch (value) {
case DateValueEnum.Today: {
endDate.setDate(today.getDate() - 1);
break;
}
// No need to do anything here because you will control the custom option with the other datepickers.
case DateValueEnum.Custom: {
return;
}
// No need for the yesterday case since there're only two cases, the custom will be handled with another function.
default: {
startDate.setDate(today.getDate() - 1);
break;
}
}
// Here you call the function that will update the parent state.
onChange({ startDate, endDate });
};
React.useEffect(() => {
if (selectedOption) {
handleChangeDateType(selectedOption.key);
}
}, [selectedOption]);
const handleChange = (option: ValueType<OptionType, false>) => {
if (option) {
setSelectedOption(option);
}
};
// This function will update the custom logic, using the object keys to update the right date
// You need to call it like this customOnChange("startDate") and this will return an onChange valid date function.
const customOnChange = (key: IDatesKeys) => (date: Date | null) => {
onChange({
...dates,
[key]: date
});
};
return (
<div>
<ReactSelect
value={selectedOption}
onChange={handleChange}
options={options}
isMulti={false}
autoFocus
/>
{selectedOption?.key === DateValueEnum.Custom && (
<div style={{ display: "flex" }}>
<div style={{ width: "50%", float: "left", paddingRight: "5px" }}>
<DatePicker
fullWidth
margin="normal"
required={true}
error={false}
invalidLabel={"Several values..."}
value={dates.startDate}
onChange={customOnChange("startDate")}
format="MM/dd/yyyy"
/>
</div>
<DatePicker
fullWidth
margin="normal"
required={true}
error={false}
invalidLabel={"Several values..."}
value={dates.endDate}
onChange={customOnChange("endDate")}
format="MM/dd/yyyy"
/>
</div>
)}
</div>
);
}

如果你想看的话,这里有一个分叉的沙箱:https://codesandbox.io/s/date-picker-forked-fyt7t

最新更新