基于JSON数据在React中实现联动多级下拉列表的求助
实现嵌套JSON数据的React联动多级下拉列表
问题描述
我是React新手,现有自行开发的API返回嵌套结构的影院JSON数据(单影院关联多部电影、场次及座位),示例数据如下:
{ "theatreId": 1, "theatreName": "Scotiabank Theater Chinook", "movies": [ { "movieId": 4, "movieName": "Now You See Me", "dateAdded": "2022-12-31", "showtimes": [ { "showtimeId": 14, "showtimeDate": "2022-12-10", "showtimeTime": "11:00:00", "seats": [ { "seatId": 218, "seatNum": 10, "theTicket": null }, { "seatId": 220, "seatNum": 12, "theTicket": null }, { "seatId": 214, "seatNum": 6, "theTicket": null }, { "seatId": 210, "seatNum": 2, "theTicket": null }, { "seatId": 219, "seatNum": 11, "theTicket": null } ] } ] } ] }
需要实现联动多级下拉列表:选影院后显示对应电影,选电影后显示对应场次,但当前代码是单独请求各层级API,无法实现关联切换,现有代码如下:
import React, {useState,useEffect} from 'react'; import axios from 'axios'; function Form() { const [theaterName, setTheaterName] = useState("") const [movieName, setMovieName] = useState("") const [showTime, setShowTime] = useState("") const [theaterList, setTheaterList] = useState([{'theatreId':''}]) const [movieList, setMovieList] = useState([{'movieId':''}]) const [showTimeList, setShowTimeList] = useState([{'showtimeId':''}]) useEffect(() =>{ fetchTheater(); fetchMovie(); fetchShowTime() }, []) const fetchTheater = () => { axios.get('http://localhost:8080/api/v1/theatre') .then(response => { console.log(response.data) setTheaterList(response.data); }) .catch(error => console.log(error)); } const fetchMovie = () => { axios.get('http://localhost:8080/api/v1/movie') .then(response => { console.log(response.data) setMovieList(response.data); }) .catch(error => console.log(error)); } const fetchShowTime = () => { axios.get('http://localhost:8080/api/v1/showtime') .then(response => { console.log(response.data) setShowTimeList(response.data); }) .catch(error => console.log(error)); } const handleTheaterChange = (event) =>{ setTheaterName(event.target.value); } const handleMovieChange = (event) =>{ setMovieName(event.target.value); } const handleShowTimeChange = (event) =>{ setShowTime(event.target.value); } const saveBtn = (e) => { e.preventDefault(); console.log('Theater Selected',theaterName); console.log('Movie Selected',movieName); console.log('Showtime Selected',showTime); } return ( <div> <div className="container-fluid"> <div className="row"> <div className="col-sm-4"> <h2 className="alert alert-warning">Movies</h2> <br /> <select className="form-control" value={theaterName} onChange={handleTheaterChange}> <option value="">Choose theatre</option> {theaterList.map(theater => ( <option key={theater.theatreId} > {theater.theatreName} </option> ))} </select> <br/> <select className="form-control" value={movieName} onChange={handleMovieChange}> <option value="">Choose Movie</option> {movieList.map(movie => ( <option value={movie.movieName} key={movie.movieId} >{"Hello"}</option> ))} </select> <br/> <select className="form-control" value={showTime} onChange={handleShowTimeChange}> <option value="">Choose showtime</option> {showTimeList.map(showtime => ( <option value={showtime.showtimeDate} key={showtime.showtimeId} >{showtime.showtimeDate}</option> ))} </select> <button className="btn btn-primary" onClick={saveBtn}>Save</button> </div> </div> </div> </div> ) } export default Form
修改后的代码
import React, { useState, useEffect } from 'react'; import axios from 'axios'; function Form() { // 保存完整的影院嵌套数据 const [theatres, setTheatres] = useState([]); // 选中的层级ID(用ID而非名称,避免名称重复问题) const [selectedTheatreId, setSelectedTheatreId] = useState(''); const [selectedMovieId, setSelectedMovieId] = useState(''); const [selectedShowtimeId, setSelectedShowtimeId] = useState(''); // 计算当前选中影院对应的电影列表 const currentMovies = selectedTheatreId ? theatres.find(t => t.theatreId === parseInt(selectedTheatreId))?.movies || [] : []; // 计算当前选中电影对应的场次列表 const currentShowtimes = selectedMovieId ? currentMovies.find(m => m.movieId === parseInt(selectedMovieId))?.showtimes || [] : []; // 仅请求一次完整的影院数据 useEffect(() => { axios.get('http://localhost:8080/api/v1/theatre') .then(response => { setTheatres(response.data); }) .catch(error => console.log(error)); }, []); const handleTheatreChange = (e) => { const theatreId = e.target.value; setSelectedTheatreId(theatreId); // 切换影院时重置电影和场次的选中状态 setSelectedMovieId(''); setSelectedShowtimeId(''); }; const handleMovieChange = (e) => { const movieId = e.target.value; setSelectedMovieId(movieId); // 切换电影时重置场次选中状态 setSelectedShowtimeId(''); }; const handleShowtimeChange = (e) => { setSelectedShowtimeId(e.target.value); }; const saveBtn = (e) => { e.preventDefault(); // 获取选中的完整信息 const selectedTheatre = theatres.find(t => t.theatreId === parseInt(selectedTheatreId)); const selectedMovie = currentMovies.find(m => m.movieId === parseInt(selectedMovieId)); const selectedShowtime = currentShowtimes.find(s => s.showtimeId === parseInt(selectedShowtimeId)); console.log('Selected Theatre:', selectedTheatre?.theatreName); console.log('Selected Movie:', selectedMovie?.movieName); console.log('Selected Showtime:', `${selectedShowtime?.showtimeDate} ${selectedShowtime?.showtimeTime}`); }; return ( <div> <div className="container-fluid"> <div className="row"> <div className="col-sm-4"> <h2 className="alert alert-warning">Movies</h2> <br /> <select className="form-control" value={selectedTheatreId} onChange={handleTheatreChange} > <option value="">Choose theatre</option> {theatres.map(theatre => ( <option key={theatre.theatreId} value={theatre.theatreId} > {theatre.theatreName} </option> ))} </select> <br /> {/* 只有选中影院后才显示电影下拉 */} {selectedTheatreId && ( <select className="form-control" value={selectedMovieId} onChange={handleMovieChange} > <option value="">Choose Movie</option> {currentMovies.map(movie => ( <option key={movie.movieId} value={movie.movieId} > {movie.movieName} </option> ))} </select> )} <br /> {/* 只有选中电影后才显示场次下拉 */} {selectedMovieId && ( <select className="form-control" value={selectedShowtimeId} onChange={handleShowtimeChange} > <option value="">Choose showtime</option> {currentShowtimes.map(showtime => ( <option key={showtime.showtimeId} value={showtime.showtimeId} > {`${showtime.showtimeDate} ${showtime.showtimeTime}`} </option> ))} </select> )} <br /> {/* 只有选中所有层级后才启用保存按钮 */} <button className="btn btn-primary" onClick={saveBtn} disabled={!selectedTheatreId || !selectedMovieId || !selectedShowtimeId} > Save </button> </div> </div> </div> </div> ); } export default Form
关键改动说明
- 数据存储优化:不再单独请求各层级API,一次性获取完整的影院嵌套数据存储在
theatres状态中,避免多次接口请求和数据关联问题。 - 用ID做选中标识:避免影院/电影名称重复导致的匹配错误,同时更精准定位嵌套数据中的对应项。
- 联动逻辑实现:
- 切换影院时,通过
find方法从theatres中提取对应电影列表,同时重置电影和场次的选中状态。 - 切换电影时,同理提取对应场次列表,重置场次选中状态。
- 切换影院时,通过
- UI交互优化:未选中上一级时隐藏下一级下拉框;保存按钮在未选全所有层级时置灰禁用,提升用户体验。
- 数据获取优化:保存时直接从嵌套数据中提取完整选中信息,无需再次请求接口。
内容的提问来源于stack exchange,提问作者Jay Jay
相关产品推荐
相关产品推荐

