我使用ReactJS更高阶函数来增强现有组件的API获取功能以及加载,错误视图。为了更加可重用,我希望使用我的HOC的另一个程序员能够添加自定义加载,这样的错误视图。
var FetchTest = fetchableContainer({
url:"https://jsonplaceholder.typicode.com/posts",
loadingView: <div>..Custom Loading..</div>,
noConnectionView: <div>.. Custom no connection view .. </div>,
errorView: <div>Custom Error View</div>
})(TestComponent);
不幸的是,它显示错误消息。
元素类型无效:需要一个字符串(用于内置组件) 或类/函数(对于复合组件)但得到:object。
有人可以用干净优雅的代码告诉我另一个解决方案。这是我的fetchableContainer。
import React, {Component} from 'react';
import axios from 'axios';
import loadingView from './loadingView.js';
import errorView from './errorView.js';
import noDataView from './noDataView.js';
import noConnectionView from './noConnectionView.js';
//redux imports
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import { Link } from 'react-router';
const fetchableContainer = (json) => (BaseComponent) => {
let url = json.url || "";
let loadingView = json.loadingView || loadingView;
let errorView = json.errorView || errorView;
let noConnectionView = json.noConnectionView || noConnectionView;
let noDataView = json.noDataView || noDataView;
class FetchableContainer extends React.Component{
constructor(props){
super(props);
this.state = {
fetchData: null,
loading: false,
fetchError: null,
interntConnection: navigator.onLine?true:false,
};
}
componentDidMount(){
this.setState({loading: true});
axios.get(this.url,{
headers: {
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods' : 'GET,PUT,POST,DELETE,PATCH,OPTIONS',
}
}).then((response)=>{
this.setState({fetchData: response.data});
this.setState({loading: false});
}).catch((error)=>{
console.log("Erorr happen");
console.log(error);
this.setState({fetchError: error});
});
}
render(){
if(!this.state.interntConnection){
return <this.noConnectionView/>;
}
if(this.state.loading){
return <this.loadingView/>;
}
if(this.state.fetchError){
return <this.errorView/>;
}
return (
<BaseComponent {...this.props}{...this.state}/>
);
}
}
}
export default fetchableContainer;
答案 0 :(得分:1)
首先,您的FetchTest
为undefined
,因为fetchableContainer
并未返回任何内容!从技术上讲,它返回一个不返回任何内容的函数。如果你真的想要使用它,你应该返回该类。
此外,这似乎是创建组件的一种奇怪方式。目前,这相当于这样做:
var FetchTest = fetchableContainer({
url:"https://jsonplaceholder.typicode.com/posts",
loadingView: <div>..Custom Loading..</div>,
noConnectionView: <div>.. Custom no connection view .. </div>,
errorView: <div>Custom Error View</div>
}, TestComponent);
容器:
//...
const fetchableContainer = (json, BaseComponent) =>
class FetchableContainer extends React.Component {
//...
}
}
export default fetchableContainer;
可能会显示错误消息,因为您尝试在某些尚未发布的代码中使用undefined
FetchTest
。
我建议以标准方式(https://redux.js.org/basics/usage-with-react#implementing-container-components)创建一个React容器,并将所需的参数传递给props
。
例如,它可能看起来像这样:
// Imports etc...
class FetchableContainer extends React.Component {
// ...
render() {
//...
return this.props.BaseComponent(/* Props */);
}
}
export default FetchableContainer;
答案 1 :(得分:0)
我刚发现错误。这是因为我传递了JSX组件并尝试获取该JSX组件。错误是通过传递返回JSX组件的函数并在FetchableContainer的render方法上获取该函数来解决的。
var FetchTest = fetchableContainer({
url: 'https://jsonplaceholder.typicode.com/posts/',
errorView: ()=> <div>Custom Error View</div>,
LoadingView:()=><div>Custom loading</div> ,
NoConnectionView: ()=> <div>Custom no Connection</div>
})(TestComponent);
我对FetchableContainer的最终代码如下。
import React, {Component} from 'react';
import axios from 'axios';
import LoadingView from './LoadingView';
import ErrorView from './ErrorView';
import NoDataView from './NoDataView';
import NoConnectionView from './NoConnectionView';
//redux imports
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import { Link } from 'react-router';
const fetchableContainer = (json) => (BaseComponent) =>{
let LoadingFetchView = json.LoadingView || LoadingView;
let fetchUrl = json.url || "https://jsonplaceholder.typicode.com/posts/";
let ErrorFetchView = json.ErrorView || ErrorView;
let NoConnectionFetchView = json.NoConnectionView || NoConnectionView;
let NoDataFetchView = json.NoDataView || NoDataView;
class FetchableContainer extends React.Component{
constructor(props){
console.log("inside constructure");
console.log(LoadingView);
super(props);
this.state = {
fetchData: null,
loading: false,
fetchError: null,
interntConnection: navigator.onLine?true:false,
};
}
componentDidMount(){
this.setState({loading: true});
axios.get(fetchUrl,{
headers: {
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods' : 'GET,PUT,POST,DELETE,PATCH,OPTIONS',
}
}).then((response)=>{
this.setState({fetchData: response.data});
this.setState({loading: false});
}).catch((error)=>{
console.log("Erorr happen");
console.log(error);
this.setState({fetchError: error});
});
}
render(){
if(!this.state.interntConnection){
return <NoConnectionFetchView/>;
}
if(this.state.loading){
return <LoadingFetchView/>;
}
if(this.state.fetchError){
return <ErrorFetchView/>;
}
return (
<BaseComponent {...this.props}{...this.state}/>
);
}
}
return FetchableContainer;
}
export default fetchableContainer;