React如何为每个列表项独立切换Watch/Watched按钮状态
问题根因
- 问题1的根因:你将包含按钮的JSX直接存入了
searchedMovies状态,生成JSX时读取的isWatched是搜索执行瞬间的状态值,后续状态更新时,已存在state中的JSX不会自动重新渲染,因此按钮文本不会变化,你的推测是正确的。 - 问题2的根因:当前只有一个全局的
isWatched状态,所有按钮共用这一个状态值,自然会同步变化,需要为每个电影单独存储观看标记。
修复方案
无需大幅重构,仅调整以下几处逻辑即可:
- 调整state结构,删除全局
isWatched,新增watchedMovies集合用来存储已标记为看过的电影名,searchedMovies仅存搜索到的电影名字符串,不存JSX - 将电影列表的渲染逻辑移到render方法中,保证状态更新时会重新计算按钮文本
- 修改
handleWatched方法,接收电影名作为参数,单独更新对应电影的观看状态
修复后完整代码
import React from 'react'; import movies from './movieData'; const movieTitles = movies.map(movie => movie.title); class SearchBar extends React.Component { constructor(props) { super(props); this.state = { searchQuery: '', searchedMovies: [], isMovieFound: null, // 用Set存储已观看的电影名,查询、更新效率更高 watchedMovies: new Set() } } handleQuery = e => { this.setState({ searchQuery: e.target.value }); } // 接收电影名作为参数,单独更新对应电影的观看状态 handleWatched = (movieName) => { this.setState(prevState => { const newWatched = new Set(prevState.watchedMovies); newWatched.has(movieName) ? newWatched.delete(movieName) : newWatched.add(movieName); return { watchedMovies: newWatched }; }); } handleSearch = () => { const matchedMovies = movieTitles.filter(movie => movie.toLowerCase().includes(this.state.searchQuery.toLowerCase()) ); if (matchedMovies.length === 0) { this.setState({ isMovieFound: false, searchedMovies: [], searchQuery: '' }); } else { this.setState({ // 只存电影名数组,不存JSX searchedMovies: matchedMovies, isMovieFound: true, searchQuery: '' }); } } render() { return ( <div> <input type="text" placeholder="Search for a movie.." name="searchQuery" value={this.state.searchQuery} onChange={this.handleQuery} /> <button onClick={this.handleSearch} > Search </button> <br /> <ul> {/* 渲染逻辑移到此处,状态更新会自动触发重新渲染 */} {this.state.searchedMovies.map(movie => ( <li key={movie}> {movie} <button className="watchBtn" onClick={() => this.handleWatched(movie)} > {this.state.watchedMovies.has(movie) ? 'Watched' : 'Watch'} </button> </li> ))} </ul> {this.state.isMovieFound === false && <span>No Movie Found</span>} </div> ); } } export default SearchBar;
内容的提问来源于stack exchange,提问作者Susie Chan
相关产品推荐
相关产品推荐

