如何使用 React Hooks 将这个级联下拉 class 组件转换为功能性组件?
How can I convert the this cascading dropdown class component to functional one using React Hooks?
我有这个 class 组件形式的级联下拉列表,它工作正常,但我想使用 React Hooks 将其转换为功能性下拉列表。这是国家、州、城市下拉列表。当用户 select 个国家/地区时,将加载其下的州。当他们 select 一个州时,将加载其下的城市。我已经更改了构造函数部分以开始使用状态,如下所示。此外,componentDidMount 已转换为 useEffect。处理程序也已转换。
但是下面显示表单的渲染部分让我很吃力。当我尝试时,我得到的错误是它没有正确排列。如何将容器 div 中的部分从使用 this.
转换为与函数的其余部分同步。我知道我必须取消 this.
但我不知道该怎么做?示例函数贴在下面。
function LocationDropdown() {
const [state, setState] = useState({
countries : [],
states : [],
lgas : [],
selectedCountry : '--Choose Country--',
selectedState : '--Choose State--'
});
useEffect(() => {
setState(prevState => ({
...prevState,
countries : [
{ name: 'Nigeria', value: 'nigeria',
states: [ {name: 'Abia', value: 'abia',
lgas: [
{name: "Aba", value: 'aba'},
{name: "Oru", value: 'oru'},
]}, {name: 'Adamawa', value: 'adamawa',
lgas: [
{name: 'Demsa', value: 'demsa'},
{name: 'Fufure', value: 'fufure'},
]},
},
]
}));
}, [])
changeCountry(event) {
this.setState({selectedCountry: event.target.value});
this.setState({states : this.state.countries.find(cntry => cntry.name === event.target.value).states});
}
changeState(event) {
this.setState({selectedState: event.target.value});
const stats = this.state.countries.find(cntry => cntry.name === this.state.selectedCountry).states;
this.setState({lgas : stats.find(stats => stats.name === event.target.value).lgas});
}
render() {
return (
<div id="container">
<h2>Cascading or Dependent Dropdown using React</h2>
<div>
<Label>Country</Label>
<Select placeholder="Country" value={this.state.selectedCountry} onChange={this.changeCountry}>
<option>--Choose Country--</option>
{this.state.countries.map((e, key) => {
return <option key={key}>{e.name}</option>;
})}
</Select>
</div>
<div>
<Label>State</Label>
<Select placeholder="State" value={this.state.selectedState} onChange={this.changeState}>
<option>--Choose State--</option>
{this.state.states.map((e, key) => {
return <option key={key}>{e.name}</option>;
})}
</Select>
</div>
<div>
<Label>LGA</Label>
<Select placeholder="LGA" value={this.state.selectedLga}>
<option>--Choose LGA--</option>
{this.state.lgas.map((e, key) => {
return <option key={key}>{e.name}</option>;
})}
</Select>
</div>
</div>
)
}
}
export default LocationDropdown;
我更改了您的代码。我重命名了 state
和 setState
,因此它不会与实际状态混淆。此外,我将 Select
和 Label
更改为正常的 html 元素,以便我可以进行测试。
import React, { useEffect, useState } from "react";
function LocationDropdown() {
const [myData, setMyData] = useState({
countries: [],
states: [],
lgas: [],
selectedCountry: "--Choose Country--",
selectedState: "--Choose State--"
});
useEffect(() => {
setMyData(prevState => ({
...prevState,
countries: [
{
name: "Nigeria",
value: "nigeria",
states: [
{
name: "Abia",
value: "abia",
lgas: [
{ name: "Aba", value: "aba" },
{ name: "Oru", value: "oru" }
]
},
{
name: "Adamawa",
value: "adamawa",
lgas: [
{ name: "Demsa", value: "demsa" },
{ name: "Fufure", value: "fufure" }
]
}
]
}
]
}));
}, []);
const mergeAndUpdateMyData = newData => {
setMyData({ ...myData, ...newData });
};
const changeCountry = event => {
mergeAndUpdateMyData({
selectedCountry: event.target.value,
states: myData.countries.find(cntry => cntry.name === event.target.value)
.states
});
};
const changeState = event => {
const stats = myData.countries.find(
cntry => cntry.name === myData.selectedCountry
).states;
mergeAndUpdateMyData({
selectedState: event.target.value,
lgas: stats.find(stats => stats.name === event.target.value).lgas
});
};
return (
<div id="container">
<h2>Cascading or Dependent Dropdown using React</h2>
<div>
<label>Country</label>
<select
placeholder="Country"
value={myData.selectedCountry}
onChange={changeCountry}
>
<option>--Choose Country--</option>
{myData.countries.map((country, key) => {
return (
<option value={country.name} key={key}>
{country.name}
</option>
);
})}
</select>
</div>
<div>
<label>State</label>
<select
placeholder="State"
value={myData.selectedState}
onChange={changeState}
>
<option>--Choose State--</option>
{myData.states.map((state, key) => {
return (
<option value={state.name} key={key}>
{state.name}
</option>
);
})}
</select>
</div>
<div>
<label>LGA</label>
<select placeholder="LGA" value={myData.selectedLga}>
<option>--Choose LGA--</option>
{myData.lgas.map((lga, key) => {
return (
<option value={lga.name} key={key}>
{lga.name}
</option>
);
})}
</select>
</div>
</div>
);
}
export default LocationDropdown;
已编辑:请注意,在 React 中,当您设置状态时,语句是异步的。这意味着当您调用 setMyData 时,myData 的值不会立即更新。所以你不能连续多次调用 mergeAndUpdateMyData 。
顺便说一句,您可以在一个功能组件中使用多个useState
。例如:
const [countries, setCountries] = useState();
const [lgas, setLags] = useState();
...
我有这个 class 组件形式的级联下拉列表,它工作正常,但我想使用 React Hooks 将其转换为功能性下拉列表。这是国家、州、城市下拉列表。当用户 select 个国家/地区时,将加载其下的州。当他们 select 一个州时,将加载其下的城市。我已经更改了构造函数部分以开始使用状态,如下所示。此外,componentDidMount 已转换为 useEffect。处理程序也已转换。
但是下面显示表单的渲染部分让我很吃力。当我尝试时,我得到的错误是它没有正确排列。如何将容器 div 中的部分从使用 this.
转换为与函数的其余部分同步。我知道我必须取消 this.
但我不知道该怎么做?示例函数贴在下面。
function LocationDropdown() {
const [state, setState] = useState({
countries : [],
states : [],
lgas : [],
selectedCountry : '--Choose Country--',
selectedState : '--Choose State--'
});
useEffect(() => {
setState(prevState => ({
...prevState,
countries : [
{ name: 'Nigeria', value: 'nigeria',
states: [ {name: 'Abia', value: 'abia',
lgas: [
{name: "Aba", value: 'aba'},
{name: "Oru", value: 'oru'},
]}, {name: 'Adamawa', value: 'adamawa',
lgas: [
{name: 'Demsa', value: 'demsa'},
{name: 'Fufure', value: 'fufure'},
]},
},
]
}));
}, [])
changeCountry(event) {
this.setState({selectedCountry: event.target.value});
this.setState({states : this.state.countries.find(cntry => cntry.name === event.target.value).states});
}
changeState(event) {
this.setState({selectedState: event.target.value});
const stats = this.state.countries.find(cntry => cntry.name === this.state.selectedCountry).states;
this.setState({lgas : stats.find(stats => stats.name === event.target.value).lgas});
}
render() {
return (
<div id="container">
<h2>Cascading or Dependent Dropdown using React</h2>
<div>
<Label>Country</Label>
<Select placeholder="Country" value={this.state.selectedCountry} onChange={this.changeCountry}>
<option>--Choose Country--</option>
{this.state.countries.map((e, key) => {
return <option key={key}>{e.name}</option>;
})}
</Select>
</div>
<div>
<Label>State</Label>
<Select placeholder="State" value={this.state.selectedState} onChange={this.changeState}>
<option>--Choose State--</option>
{this.state.states.map((e, key) => {
return <option key={key}>{e.name}</option>;
})}
</Select>
</div>
<div>
<Label>LGA</Label>
<Select placeholder="LGA" value={this.state.selectedLga}>
<option>--Choose LGA--</option>
{this.state.lgas.map((e, key) => {
return <option key={key}>{e.name}</option>;
})}
</Select>
</div>
</div>
)
}
}
export default LocationDropdown;
我更改了您的代码。我重命名了 state
和 setState
,因此它不会与实际状态混淆。此外,我将 Select
和 Label
更改为正常的 html 元素,以便我可以进行测试。
import React, { useEffect, useState } from "react";
function LocationDropdown() {
const [myData, setMyData] = useState({
countries: [],
states: [],
lgas: [],
selectedCountry: "--Choose Country--",
selectedState: "--Choose State--"
});
useEffect(() => {
setMyData(prevState => ({
...prevState,
countries: [
{
name: "Nigeria",
value: "nigeria",
states: [
{
name: "Abia",
value: "abia",
lgas: [
{ name: "Aba", value: "aba" },
{ name: "Oru", value: "oru" }
]
},
{
name: "Adamawa",
value: "adamawa",
lgas: [
{ name: "Demsa", value: "demsa" },
{ name: "Fufure", value: "fufure" }
]
}
]
}
]
}));
}, []);
const mergeAndUpdateMyData = newData => {
setMyData({ ...myData, ...newData });
};
const changeCountry = event => {
mergeAndUpdateMyData({
selectedCountry: event.target.value,
states: myData.countries.find(cntry => cntry.name === event.target.value)
.states
});
};
const changeState = event => {
const stats = myData.countries.find(
cntry => cntry.name === myData.selectedCountry
).states;
mergeAndUpdateMyData({
selectedState: event.target.value,
lgas: stats.find(stats => stats.name === event.target.value).lgas
});
};
return (
<div id="container">
<h2>Cascading or Dependent Dropdown using React</h2>
<div>
<label>Country</label>
<select
placeholder="Country"
value={myData.selectedCountry}
onChange={changeCountry}
>
<option>--Choose Country--</option>
{myData.countries.map((country, key) => {
return (
<option value={country.name} key={key}>
{country.name}
</option>
);
})}
</select>
</div>
<div>
<label>State</label>
<select
placeholder="State"
value={myData.selectedState}
onChange={changeState}
>
<option>--Choose State--</option>
{myData.states.map((state, key) => {
return (
<option value={state.name} key={key}>
{state.name}
</option>
);
})}
</select>
</div>
<div>
<label>LGA</label>
<select placeholder="LGA" value={myData.selectedLga}>
<option>--Choose LGA--</option>
{myData.lgas.map((lga, key) => {
return (
<option value={lga.name} key={key}>
{lga.name}
</option>
);
})}
</select>
</div>
</div>
);
}
export default LocationDropdown;
已编辑:请注意,在 React 中,当您设置状态时,语句是异步的。这意味着当您调用 setMyData 时,myData 的值不会立即更新。所以你不能连续多次调用 mergeAndUpdateMyData 。
顺便说一句,您可以在一个功能组件中使用多个useState
。例如:
const [countries, setCountries] = useState();
const [lgas, setLags] = useState();
...