Использование React Выберите Asyn c, каковы лучшие практики для цепочки опций.
Что я имею в виду: у меня 3 раскрывающихся списка, первый из которых заполняется по умолчанию значениями параметров, а следующие 2 раскрывающихся списка отключены.
При выборе первого раскрывающегося значения следует заполнить вторые раскрывающиеся параметры в зависимости от его значения и т. Д. Со следующим раскрывающимся списком.
, так что я пытался
import React from "react";
import Select from "react-select";
import AsyncSelect from "react-select/async";
import classnames from "classnames";
import Requests from "../services/requests";
const filterOptions = (inputValue, options) => {
return options.filter(i =>
i.label.toLowerCase().includes(inputValue.toLowerCase())
);
};
class FieldsRenderer extends React.Component {
constructor(props) {
super(props);
this.state = {
fields: props.fields,
containerClass: props.containerClass,
stepSnapshot: null,
selectOptions: {}
};
this.props.fields.map( (f) => {
if(f.type === 'select' && typeof f.dependsOn !== 'undefined') {
this.state.selectOptions[f.name] = null;
}
})
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.fields !== prevState.fields) {
return {
fields: nextProps.fields,
containerClass: nextProps.containerClass
};
}
return null;
}
componentDidUpdate(prevProps, nextProps) {
if (prevProps !== this.props) {
this.setState({
fields: nextProps.fields,
containerClass: nextProps.containerClass
});
this.props.fields.map(f => {
if (typeof f.dependsOn != "undefined") {
this.state.selectOptions[f.name] = null;
}
});
}
}
handleInputChange = (index, e) => {
console.log(e.target.value);
console.log(index);
};
handleSelectChange = (selectedOption, item) => {
this.setState({
stepSnapshot: {
[item.name]: {
value: selectedOption.value,
label: selectedOption.label
}
}
});
let childField = this.props.fields.filter(t => {
if (t.type === "select" && typeof t.dependsOn !== "undefined") {
return t.dependsOn === item.name;
}
});
if (childField) {
this.loadChildOptions(childField[0], selectedOption);
}
};
//load child slect options
loadChildOptions(target, parentValue) {
Requests.get(
process.env.REACT_APP_API_BASE_URL +
target.source +
"/" +
parentValue.value,
(status, data) => {
//data will be set but will be shown just the previous state
this.state.selectOptions[target.name] = data;
}
);
}
render() {
let containerClass = "";
let fields = this.state.fields.map((field, i) => {
const fieldType = field.type;
let fieldStyle;
if (
typeof this.state.containerClass !== "undefined" &&
this.state.containerClass !== ""
) {
containerClass = this.state.containerClass;
}
if (typeof field.width !== "undefined" && field.width !== "") {
fieldStyle = {
width: "calc(" + field.width + " - 5px)"
};
}
switch (fieldType) {
case "select": {
const selectCustomStyles = {
control: (base, state) => ({
...base,
boxShadow: state.isFocused ? 0 : 0,
borderWidth: 2,
height: 45,
borderColor: state.isFocused ? "#707070" : base.borderColor,
"&:hover": {
borderColor: state.isFocused ? "#707070" : base.borderColor
}
}),
option: (provided, state) => ({
...provided,
backgroundColor: state.isSelected ? "#46B428" : "initial"
})
};
if (
typeof field.async !== "undefined" &&
typeof field.dependsOn === "undefined"
) {
return (
<div key={i} className={"field-wrapper"}>
<AsyncSelect
loadOptions={(inputValue, callback) => {
Requests.get(
process.env.REACT_APP_API_BASE_URL + field.source,
(status, data) => {
callback(data);
}
);
}}
styles={selectCustomStyles}
defaultOptions
name={field.name}
placeholder={field.label}
onChange={this.handleSelectChange}
/>
</div>
);
} else if(typeof field.dependsOn !== "undefined") {
return(<div key={i} className={"field-wrapper"}>
<AsyncSelect
styles={selectCustomStyles}
placeholder={field.label}
defaultOptions={this.state.selectOptions[field.name]}
loadOptions={this.state.selectOptions[field.name]}
/>
</div>)
} else {
const disabled =
typeof field.dependsOn !== "undefined" && field.dependsOn !== ""
? this.state.selectOptions[field.name] != null
? false
: true
: false;
return (
<div key={i} className={"field-wrapper"}>
<Select
styles={selectCustomStyles}
placeholder={field.label}
//isLoading={this.state.selectOptions[field.name].length ? true : false}
isDisabled={disabled}
name={field.name}
options={this.state.selectOptions[field.name]}
/>
</div>
);
}
}
case "input":
{
let suffix;
let inputAppendClass;
if (typeof field.suffix !== "undefined" && field.suffix !== "") {
inputAppendClass = "input-has-append";
suffix = <span className={"input-append"}>{field.suffix}</span>;
}
return (
<div
key={i}
className={classnames("field-wrapper input", inputAppendClass)}
style={fieldStyle}
>
<input
placeholder={field.label}
type="text"
className={"input-field"}
onChange={event => this.handleInputChange(field.name, event)}
/>
{suffix}
</div>
);
}
break;
case "checkbox":
{
containerClass = "checkbox-fields";
let radios = field.options.map((option, b) => {
return (
<div key={i + b} className={"field-wrapper checkbox-button"}>
<input
placeholder={option.label}
id={option.name + "_" + i + b}
type={"checkbox"}
className={"input-field"}
/>
<label htmlFor={option.name + "_" + i + b}>
<div className={"label-name"}>{option.label}</div>
<span className={"info-icon"}></span>
<div className={"hint"}>{option.hint}</div>
</label>
</div>
);
});
return radios;
}
break;
case "radio":
{
let radios = field.options.map((option, k) => {
return (
<div key={i + k} className={"field-wrapper radio-button"}>
<input
name={option.name}
id={option.name + "_" + i + k}
placeholder={option.label}
type={"radio"}
className={"input-field"}
/>
<label htmlFor={option.name + "_" + i + k}>
<div className={"label-name"}>{option.label}</div>
<div className={"hint"}>{option.hint}</div>
</label>
</div>
);
});
return radios;
}
break;
default:
break;
}
});
return (
<div className={classnames("fields-group", containerClass)}>{fields}</div>
);
}
}
export default FieldsRenderer;