React报错:Functions are not valid as a React child 求助排查
嘿,我来帮你搞定这个React警告问题!这个报错的核心原因很明确:你把一个返回组件的函数当成了组件本身来渲染,React可不允许这么做哦。
问题分析
看你的代码,你把整个类组件和Redux connect的逻辑都包裹在了一个箭头函数里,然后默认导出了这个箭头函数。当其他地方import这个模块并尝试渲染<SchoolContentList />时,实际上是在渲染这个箭头函数本身——而React期望的是一个React组件(类组件或函数组件),不是一个返回组件的函数,所以就触发了这个警告:
warning.js:35 Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
修复方案
最规范也最简单的修复方式是去掉外层的箭头函数,直接导出经过connect处理后的组件,这是React+Redux项目导出容器组件的标准写法:
import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import ContentTable from './ContentTableBuilder'; import { setCurrentContentPage, setCurrentContent, clearContentsAfterPage, fetchLicensedContents } from '../../../../actions/library'; class SchoolContentList extends React.Component { render() { const { activeInstitution, contentType, role, contentPages, fetchLicensedContents, setCurrentContentPage, setCurrentContent, clearContentsAfterPage, } = this.props; return ( <div className="contentBox"> {/* Main Content Table */} <ContentTable {...{ recordPages: contentPages, fetchRecords: (...args) => fetchLicensedContents(contentType, role, activeInstitution.id, ...args), setCurrentRecordPage: setCurrentContentPage, setCurrentRecord: setCurrentContent, clearRecordsAfterPage: clearContentsAfterPage, }} /> </div> ); } } SchoolContentList.propTypes = { role: PropTypes.string.isRequired, activeInstitution: PropTypes.shape({ id: PropTypes.number, }).isRequired, contentPages: PropTypes.object.isRequired, fetchLicensedContents: PropTypes.func.isRequired, setCurrentContentPage: PropTypes.func.isRequired, setCurrentContent: PropTypes.func.isRequired, clearContentsAfterPage: PropTypes.func.isRequired, }; const mapStateToProps = (state) => { const auth = state.auth; return { role: auth.user.role, activeInstitution: auth.institutions.active || {}, contentPages: state.library.contentPages, }; }; const mapDispatchToProps = (dispatch) => ({ fetchLicensedContents: (contentType, q, page, perPage, sortOpts, extraFilters) => ( dispatch(fetchLicensedContents(contentType, q, page, perPage, sortOpts, extraFilters)) ), setCurrentContentPage: (page) => dispatch(setCurrentContentPage(page)), setCurrentContent: (contentId, data) => dispatch(setCurrentContent(contentId, data)), clearContentsAfterPage: (page) => dispatch(clearContentsAfterPage(page)), }); // 直接导出connect后的组件,去掉外层箭头函数 export default connect(mapStateToProps, mapDispatchToProps)(SchoolContentList);
替代方案(不推荐)
如果你非要保留外层的箭头函数(其实完全没必要),那在使用这个组件的时候,必须先调用这个函数拿到真正的组件:
// 在导入的地方 import getSchoolContentList from './SchoolContentList'; const SchoolContentList = getSchoolContentList(); // 然后正常渲染 <SchoolContentList />
但这种写法不符合React组件的常规导出方式,容易让其他开发者困惑,所以更推荐第一种方案。
总结
这个警告的本质是React渲染了一个函数而非合法的React元素。只要把外层的包裹箭头函数去掉,直接导出connect处理后的组件,问题就解决啦!
内容的提问来源于stack exchange,提问作者user9848916

