Ken*_*hin 1 reactjs material-ui
我有两个自动完成组件和一个元素,单击该元素会在两个自动完成组件之间切换值。当我这样做时,我也会切换选项。在自动完成组件中,我正在使用所选值渲染隐藏字段。当我单击切换值的元素时,我可以在 DOM 中看到隐藏字段在 2 个自动完成组件之间正确更新。当我单击下拉菜单时,我还可以看到正在切换的选项。但标签/文本字段没有更新。原始标签将保留,不会更新为新标签。
父组件:
import React, { useState, useEffect, Suspense } from 'react';
import classes from './AirForm.module.css';
const AirType = React.lazy(() => import('./Controls/Air/AirType'));
const Airport = React.lazy(() => import('./Controls/Air/Airport'));
const AirForm = props => {
const [airTypeSelected, setAirTypeSelected] = useState('RoundTrip');
const [fromSelected, setFromSelected] = useState();
const [fromOptions, setFromOptions] = useState([]);
const [toSelected, setToSelected] = useState();
const [toOptions, setToOptions] = useState([]);
//const [switchFromTo, setSwitchFromTo] = useState(true);
const switchFromToHandler = () => {
setFromOptions(toOptions);
setToOptions(fromOptions);
setFromSelected(toSelected);
setToSelected(fromSelected);
//setSwitchFromTo(!switchFromTo);
}
//useEffect(() => {
// setFromSelected(toSelected);
// setToSelected(fromSelected);
//}, [switchFromTo]);
return (
<Suspense>
<AirType airTypeSelected={airTypeSelected} setAirTypeSelected={setAirTypeSelected} />
<form action={props.data.AirUrl} method="post">
<div className={classes.destinations}>
<div>
<Airport data={props.data} name="DepartureAirport" label="From" options={fromOptions} setOptions={setFromOptions} optionSelected={fromSelected} setOptionSelected={setFromSelected} onSwitch={switchFromToHandler} includeSwitch={true} />
</div>
<div>
<Airport data={props.data} name="ArrivalAirport" label="To" options={toOptions} setOptions={setToOptions} optionSelected={toSelected} setOptionSelected={setToSelected} includeSwitch={false} />
</div>
</div>
</form>
</Suspense>
);
}
export default AirForm;Run Code Online (Sandbox Code Playgroud)
包含自动完成组件的组件:
import React, { useState, useMemo, useEffect, useRef } from 'react';
import Styles from '../../../../../Theming/Styles';
import classes from './Airport.module.css';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';
import CircularProgress from '@mui/material/CircularProgress';
import { debounce } from '@mui/material';
const Airport = props => {
const [inputValue, setInputValue] = useState('');
const [searching, setSearching] = useState(true);
const [loading, setLoading] = useState(false);
const abortConRef = useRef();
const fetchData = useMemo(() =>
debounce((request, callback) => {
if (!props.data.AirportLookupUrl) {
callback({ success: false });
return;
}
if (abortConRef.current) abortConRef.current.abort();
abortConRef.current = new AbortController();
fetch(props.data.AirportLookupUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ q: request }),
signal: abortConRef.current.signal
})
.then(response => response.json())
.then(result => {
callback(result);
})
.catch((error) => {
if (error.name !== 'AbortError') {
throw error;
}
});
}, 400),
[]
);
useEffect(() => {
if (inputValue === '') {
props.setOptions([]);
return undefined;
}
setLoading(true);
setSearching(true);
fetchData(inputValue, (result) => {
setLoading(false);
setSearching(false);
if (result.success) {
const newOptions = result.value.map(val => {
const label = `(${val.Code})${val.City && ' ' + val.City} - ${val.Name}`;
return {
label: label,
value: val.Code
};
});
props.setOptions(newOptions);
} else {
props.setOptions([]);
}
});
}, [inputValue, fetchData]);
return (
<>
<Autocomplete
disablePortal
options={props.options}
value={props.optionSelected}
autoComplete
autoHighlight={true}
includeInputInList
fullWidth
onChange={(event, value) => { props.setOptionSelected(value); }}
onInputChange={(event, value) => {
if (event.type === 'change') {
setInputValue(value);
}
}}
noOptionsText={searching ? 'Type to search' : 'No options'}
loading={loading}
sx={Styles}
renderInput={(params) => (
<>
<input type="hidden" name={props.name} value={props.optionSelected?.value} />
<TextField
{...params}
label={props.label}
InputProps={{
...params.InputProps,
endAdornment: (
<>
{loading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</>
)
}}
/>
</>
)}
/>
{props.includeSwitch && <div onClick={props.onSwitch} className={classes.switch}><i class="fas fa-sync" aria-hidden="true"></i></div>}
</>
);
};
export default Airport;Run Code Online (Sandbox Code Playgroud)
更新
这是一个代码沙箱。不知道为什么它没有在 stackoverflow 中运行,但如果您导航到沙箱,它就会运行。https://codesandbox.io/s/strange-hertz-d8rtb8 如果您在任一自动完成组件中选择一个选项,然后单击切换按钮,您将看到选项已切换,但所选选项不会更改。每个自动完成都会呈现一个隐藏字段,当您单击切换按钮时,您可以看到隐藏字段的值已正确更新,但自动完成显示的文本值永远不会更新。
<iframe src="https://codesandbox.io/embed/strange-hertz-d8rtb8?fontsize=14&hidenavigation=1&theme=dark"
style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
title="strange-hertz-d8rtb8"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>Run Code Online (Sandbox Code Playgroud)
更新2
问题是因为我没有设置所选选项的初始状态。设置状态已解决该问题。
小智 5
解决方案:
要解决您的codesandbox问题,您需要两个步骤来解决您的问题;
null将选定的 useStates设为初始值App.js const [fromSelected, setFromSelected] = useState(null);
const [toSelected, setToSelected] = useState(null);
Run Code Online (Sandbox Code Playgroud)
onInputChange event在内部添加可选的链接MyAutocomplete。由于输入更改发生在受控状态下,这不是一个事件并且失败了。onInputChange={(event, value) => {
if (event?.type === "change") {
setInputValue(value);
}
}}
Run Code Online (Sandbox Code Playgroud)
建议:
我还可以在这里建议一些可能的改进;
const [options, setOptions] = useState({
from: {
selected: null,
options: fromList
},
to: {
selected: null,
options: toList
}
});
//
const handleSetOptions = (area, key, value) => {
setOptions({
...options,
[area]: {
...options[area],
[key]: value
}
});
};
//From Autocompolete Props, To is same just need to change from in here
options={options.from.options}
setOptions={(value) => handleSetOptions("from", "options", value)}
optionSelected={options.from.selected}
Run Code Online (Sandbox Code Playgroud)
const switchFromToHandler = () => {
setOptions((prevOptions) => ({
from: prevOptions.to,
to: prevOptions.from
}));
};
Run Code Online (Sandbox Code Playgroud)
您可以检查codesandbox的更新版本
| 归档时间: |
|
| 查看次数: |
10369 次 |
| 最近记录: |