为什么在useEffect中调用setState后组件没有触发重新渲染?
useEffect调用setState后组件未重新渲染问题排查与解决
问题描述
请问为什么我在useEffect内部调用setState后组件没有重新渲染?我在谷歌上搜索到的资料显示,在useEffect中调用setState会触发组件重新渲染。
我的代码如下:
export default function CarouselMusicGenres() { const [musicGenres, setMusicGenres] = useState(null) const setAllMusicGenres = () => { MusicGenresAPI.getAll() .then((response) => { if (response.status === 200) { setMusicGenres(response.data.musicGenres) } }) .catch((error) => { console.log(error) }) } const displayAllMusicGenres = () => { if (musicGenres && musicGenres.length > 0) { musicGenres.forEach((musicGenre) => { return ( <SwiperSlide> <Col className="genre" style={{ backgroundImage: `url(/assets/images/music-genres/${musicGenre.image_background_url})`, }} > <span>{musicGenre.genre}</span> <div className="transparent-background"></div> </Col> </SwiperSlide> ) }) } } useEffect(() => { setAllMusicGenres() }, []) return ( <Row className="carousel-genres"> <Swiper spaceBetween={10} slidesPerView={6}> {displayAllMusicGenres()} </Swiper> </Row> ) }
我还尝试过用以下代码替代useEffect逻辑,问题依然没有解决:
if (!musicGenres) { setAllMusicGenres() }
问题根因
你的组件实际上已经触发了重渲染,问题出在displayAllMusicGenres方法的实现上:forEach方法仅遍历数组,本身没有返回值,你在forEach回调中返回的JSX元素不会被收集,所以整个displayAllMusicGenres函数最终返回的是undefined,页面自然不会渲染出内容,看起来就像没有触发重渲染一样。
解决方案
将forEach替换为map,同时在musicGenres.map前添加return语句,修改后的displayAllMusicGenres代码如下:
const displayAllMusicGenres = () => { if (musicGenres && musicGenres.length > 0) { // 把forEach换成map,外层加return return musicGenres.map((musicGenre) => ( <SwiperSlide key={musicGenre.id /* 建议添加唯一key,避免React告警 */}> <Col className="genre" style={{ backgroundImage: `url(/assets/images/music-genres/${musicGenre.image_background_url})`, }} > <span>{musicGenre.genre}</span> <div className="transparent-background"></div> </Col> </SwiperSlide> )) } }
额外优化建议:渲染列表元素时最好给每一项添加唯一的key属性,可以避免React的列表渲染告警,优化重渲染性能。
内容的提问来源于stack exchange,提问作者mehdibe
相关产品推荐
相关产品推荐

