【问题标题】:Alternative ways to pass react component into higher order function将反应组件传递给高阶函数的替代方法
【发布时间】:2018-11-27 12:48:00
【问题描述】:

我正在使用 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);

不幸的是,它显示错误消息。

元素类型无效:应为字符串(用于内置组件) 或类/函数(用于复合组件)但得到:对象。

谁能告诉我另一个代码简洁优雅的解决方案。这是我的 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;

【问题讨论】:

    标签: reactjs higher-order-functions higher-order-components


    【解决方案1】:

    首先,您的FetchTestundefined,因为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 Container,并将您需要的参数作为 props 传递。

    例如,它可能看起来像这样:

    // Imports etc...
    
    class FetchableContainer extends React.Component {
        // ...
        render() {
            //...
            return this.props.BaseComponent(/* Props */);
        }
    }
    
    export default FetchableContainer; 
    

    【讨论】:

    • 你是对的。我的错误信息不是因为我将 JSX 传递给 json 值。而是因为我的 FetchableContainer 渲染了不正确的变量。
    • 是的,创建这样的组件可能很奇怪。我现在正在尝试应用高阶组件以获得更多可重用的组件。您可以在这里查看“reactjs.org/docs/higher-order-components.html".Thanks以引起您的注意.
    • 在您阅读了 HOC(高阶组件)之后,请在下面查看我的 FetchableContainer 最终版本代码。
    • 我上面给出的示例都是 HOC,因为从您链接的文档中,HOC“是一个接受组件并返回新组件的函数”。我建议的更改(在我看来;加一点盐!)使代码看起来更干净,因为您的 fetchableContainer 是一个返回一个返回组件的函数的函数,而我的只是一个返回组件的函数。据我所知,您发布的代码将起作用! HTH!
    【解决方案2】:

    我刚刚发现错误。这是因为我正在传递 JSX 组件并试图获取该 JSX 组件。通过传递返回 JSX 组件的函数并像这样在 FetchableContainer 的渲染方法上获取该函数来解决该错误。

    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;
    

    【讨论】:

      猜你喜欢
      • 2019-05-18
      • 1970-01-01
      • 1970-01-01
      • 2019-06-19
      • 1970-01-01
      • 2016-06-09
      • 2018-11-01
      • 2019-03-03
      相关资源
      最近更新 更多