React子组件componentDidMount未获父组件props且调用两次问题
兄弟,我来帮你捋捋这个问题!你遇到的情况大概率是两个原因叠加导致的:
1. React 18 Strict Mode 触发的两次挂载
React 18在开发环境下开启Strict Mode时,会自动重复执行一次挂载相关的生命周期(包括componentDidMount),这是官方特意设计的——用来帮你检测代码里有没有未清理的副作用(比如订阅、定时器没销毁)。生产环境下这个行为会自动消失,所以不用担心线上出问题。
如果你想验证是不是这个原因,去看看你的根组件(比如index.js)是不是被<StrictMode>包裹着:
// 类似这样的代码 ReactDOM.createRoot(document.getElementById('root')).render( <StrictMode> <App /> </StrictMode> );
要是暂时不想看到这个现象,可以先注释掉<StrictMode>,但更推荐保留它,毕竟能提前发现潜在问题。
2. 初始props为空的原因
你的父组件Members初始state里interests是空数组,所以第一次渲染子组件时,子组件拿到的props自然是空的。等componentDidMount里的fetch请求完成、父组件更新state后,子组件会重新渲染,但componentDidMount只会在挂载时执行(即使Strict Mode下执行两次,第一次也是空props)。
怎么解决props为空的问题?
你需要在子组件里监听props的变化,而不是只依赖componentDidMount:
如果子组件是类组件:
用componentDidUpdate配合componentDidMount,确保数据到位后再处理逻辑:
class ChildComponent extends Component { componentDidMount() { this.handleInterests(this.props.interests); } componentDidUpdate(prevProps) { // 只有当interests真的变化时才执行逻辑 if (prevProps.interests !== this.props.interests) { this.handleInterests(this.props.interests); } } handleInterests(interests) { // 先判断数据是否存在,避免空值操作 if (interests.length === 0) return; // 这里写你的业务逻辑,比如渲染数据、调用接口等 console.log('拿到有效数据啦:', interests); } render() { return ( <div> {this.props.interests.map(interest => ( <div key={interest.id}>{interest.name}</div> ))} </div> ); } }
如果换成函数组件(更推荐React 18的写法):
用useEffect监听interests的变化:
import { useEffect } from 'react'; function ChildComponent({ interests }) { useEffect(() => { if (interests.length === 0) return; // 处理逻辑 console.log('有效数据已更新:', interests); }, [interests]); // 依赖数组里加interests,数据变化时自动执行 return ( <div> {interests.map(interest => ( <div key={interest.id}>{interest.name}</div> ))} </div> ); }
额外排查点
还要确认父组件的fetch请求是不是真的成功了:可以在then回调里加日志,看看有没有拿到数据,以及authToken是不是正确传递了,避免因为请求失败导致interests一直是空数组。
内容的提问来源于stack exchange,提问作者Dieguinho

