在React useEffect中使用TypeScript对电影对象数组排序遇阻求助
解决React useEffect中电影数组排序的TypeScript类型问题
我来帮你拆解并解决这两个TypeScript错误,同时优化你的排序逻辑:
先分析错误原因
返回布尔值的错误
你把sortArray定义成了类型谓词函数(返回sortProperty is keyof typeof types),这类函数的作用是做类型判断,必须返回boolean,但你却在函数里返回了排序后的数组,自然会触发类型不匹配的报错。这个函数的定位完全错了,它应该是一个返回排序后数组的工具函数,而非类型守卫。索引类型错误
之前sortProperty是string类型,TypeScript无法确认这个字符串是否是Movie接口的合法属性键,所以不允许用来索引Movie对象。你需要把排序属性的类型限定为keyof Movie,才能让TypeScript确认索引的安全性。
修正后的完整代码
我会用更符合React最佳实践的方式重构你的代码,同时解决类型问题:
import React, { useState, useEffect, useMemo } from 'react'; import { useHistory } from 'react-router-dom'; import Requests from './Requests'; export interface Movie { comments: string; imdb: string; mtc: string; rtc: string; smn: string; title: string; } const Database = () => { const [movies, setMovies] = React.useState<Movie[]>([]); // 把排序类型限定为Movie的属性键,从根源避免无效属性传入 const [sortConfig, setSortConfig] = useState<{ key: keyof Movie; direction: 'asc' | 'desc'; }>({ key: 'title', direction: 'asc' }); const history = useHistory(); // 仅在组件挂载时请求一次电影数据 useEffect(() => { Requests.getMovies() .then(fetchedMovies => setMovies(fetchedMovies)) .catch(err => console.error('获取电影数据失败:', err)); }, []); // 用useMemo缓存排序结果,只有movies或sortConfig变化时才重新排序 const sortedMovies = useMemo(() => { if (movies.length === 0) return []; return [...movies].sort((a, b) => { const valueA = a[sortConfig.key]; const valueB = b[sortConfig.key]; // 区分字符串和数字字符串的排序逻辑 if (sortConfig.key === 'title') { // 标题按字母顺序排序 const compareResult = valueA.localeCompare(valueB); return sortConfig.direction === 'asc' ? compareResult : -compareResult; } else { // 评分/评论数字符串转成数字比较 const numA = parseFloat(valueA); const numB = parseFloat(valueB); const compareResult = numA - numB; return sortConfig.direction === 'asc' ? compareResult : -compareResult; } }); }, [movies, sortConfig]); // 切换排序规则的工具函数(支持升序/降序切换) const handleSortChange = (key: keyof Movie) => { let direction: 'asc' | 'desc' = 'asc'; if (sortConfig.key === key && sortConfig.direction === 'asc') { direction = 'desc'; } setSortConfig({ key, direction }); }; return ( <div> {/* 排序选择栏(支持多属性+升降序切换) */} <div className="sort-controls"> <button onClick={() => handleSortChange('title')}> 标题 {sortConfig.key === 'title' && (sortConfig.direction === 'asc' ? '↑' : '↓')} </button> <button onClick={() => handleSortChange('imdb')}> IMDB评分 {sortConfig.key === 'imdb' && (sortConfig.direction === 'asc' ? '↑' : '↓')} </button> <button onClick={() => handleSortChange('rtc')}> 烂番茄评分 {sortConfig.key === 'rtc' && (sortConfig.direction === 'asc' ? '↑' : '↓')} </button> </div> {/* 渲染排序后的电影列表 */} <div className="movie-list"> {sortedMovies.map(movie => ( <div key={movie.imdb} className="movie-card"> <h3>{movie.title}</h3> <p>IMDB: {movie.imdb} | 烂番茄: {movie.rtc}</p> <p>评论数: {movie.comments}</p> </div> ))} </div> </div> ); }; export default Database;
关键优化点说明
- 类型安全强化:把
sortConfig.key的类型限定为keyof Movie,确保只能传入Movie接口中定义的属性,彻底解决索引类型错误。 - 用useMemo替代useEffect排序:避免在副作用里直接修改状态,同时缓存排序结果,提升性能(只有依赖项变化时才重新排序)。
- 支持多属性+升降序扩展:通过
sortConfig对象同时记录排序属性和方向,后续扩展其他属性排序只需要添加对应的按钮和逻辑即可。 - 区分不同类型的排序逻辑:标题用字符串的
localeCompare做字母排序,评分/评论数转成数字后做数值排序,确保排序行为符合预期。
内容的提问来源于stack exchange,提问作者daritimm
相关产品推荐
相关产品推荐

