有一个名为Document的组件,用于显示文档的详细信息。
Document.js
export class Document extends Component {
componentDidMount () {
if (this.props.documentId) {
this.props.fetchDocument(this.props.documentId)
}
}
render () {
const {document} = this.props
if (!document) {
return <div>No document yet</div>
}
return (
<div>
<h1>Document {document.name}</h1>
</div>
)
}
}
Document.propTypes = {
documentId: PropTypes.string.isRequired,
document: PropTypes.object.isRequired,
fetchDocument: PropTypes.func.isRequired,
}
使用DocumentContainer中的redux connect()函数创建Document组件。
DocumentContainer.js
const mapStateToProps = (state, ownProps) => {
const {documentId} = ownProps.match.params
const document = state.documents.items[documentId]
return {
documentId: documentId,
document: document,
}
}
const mapDispatchToProps = dispatch => {
return {
fetchDocument: (documentId) => {
dispatch(fetchDocument(documentId))
},
}
}
const DocumentContainer = connect(
mapStateToProps,
mapDispatchToProps
)(Document)
export default DocumentContainer
名为App的主要组件路由到DocumentContainer组件。
App.js
class App extends Component {
render () {
return (
<div>
<Switch>
<Route path="/document/:documentId" component={DocumentContainer}/>
</Switch>
</div>
)
}
}
export default withRouter(connect(mapStateToProps)(App))
问题是Document组件将文档作为必需的propType。但是在组件安装之后,文档才会被加载(调用动作fetchDocument)。所以我收到了这个警告:
index.js:2177警告:道具类型失败:道具
document
已标记 根据{{1}}的要求,但其值为Document
是否有解决此问题的最佳做法?
我考虑的解决方案:
- 创建另一个名为DocumentLoader的组件,并在App中路由到该组件。然后,DocumentLoader将加载文档,并仅在文档加载后呈现Document组件。缺点是需要创建另一个组件。
- 使用ownProps.match.params将文档加载到App组件的mapStateToProps函数中。然而,当App组件中需要加载10个其他组件时,这会变得很痛苦,而且我放弃了react-router-dom的一些简单性。
我最终做了以下事情:
- 将fetchDocument从componentDidMount移动到组件Document中的componentWillMount
- 在提取开始后,将undefined
添加到设置为isLoading
的状态
- 在DocumentContainer中将true
添加到document ? document : {},
- 将mapStateToProps
替换为if(!document)
我仍然不确定的是,它是否是获取组件本身数据的最佳解决方案,或者是否有更好的方法。我没有找到任何资源来解释如何以任何其他方式执行此操作(例如,使用中间件)。
答案 0 :(得分:1)
您需要将获取文档逻辑移至componentWillMount
生命周期。
componentWillMount () {
if (this.props.documentId) {
this.props.fetchDocument(this.props.documentId)
}
}
通常,您也不会在组件中调用fetch
。你想使用某种中间件。当您开始提取文档时,您在商店中将isLoadingDocument
标记为true
。然后,不要执行if(!document)
,而是执行if(isLadingDocument)
。
答案 1 :(得分:0)
您已经处理过渲染函数中未定义文档的情况:
if (!document) {
return <div>No document yet</div>
}
因此,您可以从isRequired
移除document: PropTypes.object.isRequired,
document: PropTypes.object,
。
由于您不需要document
但未定义defaultProp
,因此可能会出现掉落错误。要解决此问题,您可以指定defaultProps:
Document.defaultProps = {
document: undefined,
};
答案 2 :(得分:0)
你可以在这里再考虑一件事,检查容器组件本身是否有文档,如果它不可用,只需返回一个空对象。
const mapStateToProps = (state, ownProps) => {
const {documentId} = ownProps.match.params
const document = state.documents.items[documentId]
return {
documentId: documentId,
document: document ? document : {},
}
}
你还应该检查Document组件中的空对象,如下所示,
const {document} = this.props
if (Object.keys(document).length === 0) {
return <div>No document yet</div>
}
return (
<div>
<h1>Document {document.name}</h1>
</div>
)