使用slice()触发TypeError,求Pokemon列表分页解决方案
问题修复方案
错误根源
你碰到的TypeError: Cannot read properties of null (reading 'slice'),是因为组件初始化时state.pokemon设为了null,而displayUsers的定义早于return中的条件渲染逻辑。第一次render时,代码会直接对null调用slice方法,触发报错——哪怕后面有this.state.pokemon ? ...的判断,也来不及阻止错误发生,因为代码执行顺序是先计算displayUsers再进入条件分支。
具体修复步骤
1. 修正初始state的pokemon值
把state里的pokemon: null改成pokemon: [],空数组可以安全调用slice和map方法,不会触发报错:
state = { url: "https://pokeapi.co/api/v2/pokemon?limit=100000&offset=0", pokemon: [], // 替换null为空数组 pageNumber: 1, pokemonsPerPage: 16 };
2. 修复分页计算逻辑
当前pagesVisited = this.state.pageNumber * this.state.pokemonsPerPage会导致第一页从第17个元素开始(pageNumber=1时,1*16=16),正确的起始位置应该是(pageNumber-1)*pokemonsPerPage:
const pagesVisited = (this.state.pageNumber - 1) * this.state.pokemonsPerPage;
3. 优化条件渲染判断
空数组在JavaScript中属于truthy值,原来的this.state.pokemon ? ...会显示空的div.row,应该改成判断数组长度,确保无数据时显示加载提示:
{this.state.pokemon.length > 0 ? ( <div className='row'> {displayUsers} </div> ) : (<h2>Loading Pokemon</h2>)}
可选方案:添加空值保护(不修改初始state的情况)
如果坚持初始pokemon为null,可以在定义displayUsers时加一层空值判断:
const displayUsers = this.state.pokemon ? this.state.pokemon.slice(pagesVisited, pagesVisited + this.state.pokemonsPerPage) .map((pokemon) => { return ( <PokemonCard key={pokemon.name} name={pokemon.name} url={pokemon.url} /> ) }) : []
修复后的完整代码
import React, { Component } from 'react' import axios from 'axios' import ReactPaginate from 'react-paginate'; import PokemonCard from './PokemonCard'; export default class PokemonList extends Component { state = { url: "https://pokeapi.co/api/v2/pokemon?limit=100000&offset=0", pokemon: [], pageNumber: 1, pokemonsPerPage: 16 }; async componentDidMount() { const res = await axios.get(this.state.url); console.log(res.data['results']); this.setState({pokemon: res.data['results']}); }; render() { console.log(this.state.pokemon); const pagesVisited = (this.state.pageNumber - 1) * this.state.pokemonsPerPage; const displayUsers = this.state.pokemon .slice(pagesVisited, pagesVisited + this.state.pokemonsPerPage) .map((pokemon) => { return ( <PokemonCard key={pokemon.name} name={pokemon.name} url={pokemon.url} /> ) }) return ( <React.Fragment> {this.state.pokemon.length > 0 ? ( <div className='row'> {displayUsers} </div> ) : (<h2>Loading Pokemon</h2>)} </React.Fragment> ) } }
内容的提问来源于stack exchange,提问作者Amaury Gimonnet
相关产品推荐
相关产品推荐

