React函数组件中子组件无法加载父组件传递的属性问题排查
问题原因分析
- 父组件初始未使用状态管理数据,普通变量更新不会触发React重渲染
最开始用var声明servicesList时,React不会监听普通JS变量的变化,给servicesList赋值后父组件不会重新渲染,子组件接收到的props永远是初始空值。 - 父组件未给子组件传递
ServicesList属性
你父组件返回的<ServiceGrid />仅传递了OperationalProcessSelector,完全没有传递ServicesList属性,子组件的props.ServicesList永远是初始空值,即便父组件改用useState也无法生效。 - 子组件
useEffect依赖项配置错误
子组件用于同步props的useEffect依赖项是空数组,只会在组件第一次挂载时执行一次,后续父组件传递的ServicesList更新后,这个effect不会重新触发,自然不会更新子组件的tableData。
修复方案
第一步:父组件改用useState管理数据,正确传递props
const Parent = () => { const selectedProduct = 0; // 用useState管理数据,更新时会触发组件重渲染 const [servicesList, setServicesList] = useState<IService[]>([]); const [operationalProcessSelector, setOperationalProcessSelector] = useState<IOperationalProcessSelector[]>([]); useEffect(()=>{ fetchServicesList(840); }, []); const fetchServicesList = async (quotationId: number) => { const SERVICE_LIST_API_URL = `API URL...`; const response = await axios.get(SERVICE_LIST_API_URL, {headers:API_REQ_HEADERS}) if(response && response.data && response.data.length > 0 && response.data[0]){ let product = response.data[selectedProduct]; let operationalProcesses = product.OperationalProcess; updateServiceList(operationalProcesses); } }; const updateServiceList = (operationalProcesses: any) => { operationalProcesses.forEach((operationalProcessItem: any)=>{ operationalProcessItem.Services.forEach((serviceItem: any) => { serviceItem.LineEditState = 'edit'; serviceItem.ShowContent = true; }); }); const flattenedArray: IService[] = operationalProcesses.reduce( (accumulator: IService[], value: any) => accumulator.concat(value.Services), [] as IService[] ); // 调用set方法更新状态,触发父组件重渲染 setServicesList(flattenedArray); console.log('Update Services', flattenedArray); }; // 给子组件传递ServicesList属性 return <ServiceGrid OperationalProcessSelector={operationalProcessSelector} ServicesList={servicesList} /> } export default Parent
第二步:子组件正确监听props变化,同步更新本地状态
你后续需要在子组件修改数据并触发渲染,子组件本地维护tableData状态的方案是合理的,只需将props.ServicesList加入useEffect依赖项,props变化时自动同步即可:
const ServiceGrid = (props: Prop) => { console.log("Component ServiceGrid generated"); const [tableData, setTableData] = useState<IService[]>(props.ServicesList); // 把props.ServicesList加入依赖项,父组件传的列表更新时自动同步到子组件状态 useEffect(()=>{ setTableData(props.ServicesList); console.log('component', props.ServicesList); }, [props.ServicesList]); return ( // 渲染前加判空逻辑,避免初始空数组时报错 <div>{tableData?.map((e: any)=>e.childData)}</div> ); }; export default ServiceGrid; interface Prop { OperationalProcessSelector: IOperationalProcessSelector[], ServicesList: IService[] }
额外说明
如果子组件修改的数据只需要在子组件内生效,直接调用setTableData更新即可自动触发渲染。如果修改后的数据需要同步回父组件,建议把修改逻辑提升到父组件,父组件传递修改方法给子组件调用,避免父子组件状态不一致。
内容的提问来源于stack exchange,提问作者Kirk
相关产品推荐
相关产品推荐

