代码之家  ›  专栏  ›  技术社区  ›  Samiksha Jagtap

如何在调用高阶组件时访问类外属性,以便高阶组件可以重用

  •  2
  • Samiksha Jagtap  · 技术社区  · 8 年前

    如果数据不可用,我已经创建了更高阶的组件来呈现加载程序。组件命名为 装载机 是高阶分量。组件命名为 联系人列表 调用高阶组件。 我的联系人列表组件代码:

    import React, { Component } from 'react';
    import '../App.css';
    import Loader from './hoc/Loader.js';
    
    class ContactList extends Component {
      constructor(props) {
        super(props);
        this.state = {
        }
      }
    
     render() {
       return (
         <div className="App">
           {
            this.props.contacts.map((contact, index) => (
              <div key={index}>
                <p>{contact.name}</p>
              </div>
            ))
          }
        </div>
       );
      }
    }
    
    export default Loader(this.props.contacts)(ContactList);
    

    加载程序(hoc)组件的代码-

    import React, { Component } from 'react';
    import './Loader.css';
    
    const Loader = (propName) => (WrappedComponent) => {
        return class Loader extends Component {
            isEmpty(prop) {
                return (
                    prop === null ||
                    prop === undefined ||
                    (prop.hasOwnProperty('length') && prop.length === 0) ||
                    (prop.constructor === Object.keys(prop).length === 0)
                );
            }
            render() {
                return this.isEmpty(propName) ? <div className="loader"></div> : <WrappedComponent {...this.props}/>
            }
        }
    }
    
    export default Loader;
    

    但我犯了个错误

    uncaught typeerror:无法读取未定义的属性“contacts” 因为道具在课外是不可接近的。

    我试过很多办法-

    (一) one of tried solution

    2)如果我将出口报表更改为 export default Loader(ContactList) ,则此操作正常,但加载程序组件不再可重用。

    5 回复  |  直到 8 年前
        1
  •  1
  •   Azamat Zorkanov    8 年前

    在这里:

    export default Loader(this.props.contacts)(ContactList);
    

    你想在课外接触道具。从联系人列表类中访问它们是不可能的。

    编辑

    如果需要显示loader,取决于 联络 数组,你不需要使用hoc。只需在模板中使用加载程序:

    <Loader contacts={this.props.contacts}>
          {
            this.props.contacts.map((contact, index) => (
              <div key={index}>
                <p>{contact.name}</p>
              </div>
            ))
          }
    </Loader>
    

    注意,在这种情况下,您必须使加载程序只是一个组件,而不是hoc 是的。

    这里是这种情况的例子:

    class Loader extends React.Component {
      render(){
        const {values} = this.props;
        if (values.length) {
           return this.props.children;
        }
        return <div>Loading...</div>
      }
     }
    

    并在contactList组件中使用它:

    import React, { Component } from 'react';
    import '../App.css';
    import Loader from './hoc/Loader.js';
    
    class ContactList extends Component {
      constructor(props) {
        super(props);
        this.state = {
        }
      }
    
     render() {
       return (
         <div className="App">
           <Loader values={this.props.contacts}>
           {
            this.props.contacts.map((contact, index) => (
              <div key={index}>
                <p>{contact.name}</p>
              </div>
            ))
          }
          </Loader>
        </div>
       );
      }
    }
    
    export default ContactList;
    

    加载程序组件只是一个例子,使用您自己的加载程序。 正如我所说,没有必要使用hoc。无论如何,您的加载程序组件将是可重用的,因为您也可以在不同的组件中使用它。希望这有帮助

        2
  •  0
  •   Nima habibkhoda    8 年前

    导出默认加载程序(this.props.contacts)(contactList);

    这是错误的,您必须在类外部设置一个let变量,并在类内部设置它,然后在那里调用它

        3
  •  0
  •   Praveen Rao Chavan.G    8 年前

    你的代码应该是这样的

    临时:

    const Loader = (props) => (WrappedComponent) => (moreProps) => {
    const ContactList = props.ContactList;
     return (
       <Wrapper>
         <Container>
           <WrappedComponent {...moreProps} />
         </Container>
       </Wrapper>
     )
    }
    

    现在你可以这样用了

    export default Loader({ [ 'Praveen', 'Hari', 'Swamy' ] })(ContactList)
    
        4
  •  0
  •   Dacre Denny    8 年前

    问题似乎是您试图访问道具的方式:

    export default Loader(this.props.contacts /* <-- this is incorrect */ )(ContactList);
    

    重新考虑一下情况-你想达到什么目的?做什么 this 意思是在你的单元里?

    通常在使用hoc时,您会发现出现类似的模式:

    export default Loader(ContactList);
    

    哪个(取决于 Loader )然后允许您导入该组件(即loadercontactlist)并传递道具“通过” 装载机 从内到内 ContactList 具体如下:

    <LoaderContactList contacts={ [ 'bob', 'joe', 'mary' ] } />
    

    希望这能提供一些澄清。

    说明HOF/HOC概念的更新

    要说明我的答案中描述的hoc概念,请参见以下内容:

    export function(InnerComponent) { // This is the higher-order-function to export (ie Loader)
    
        return class OuterComponent extends Component { // This is the higer-order-component
    
            render() {
                /* To illustrate the possiblitiy of reusable code via HOC's, 
                   this HOC responds to an generic 'isBusy' prop by returning 
                   a loading message if truthy */
                if(this.props.isBusy) {
                    return <p>Loading</p>
                }
    
                /*
                Otherwise, the inner component that you pass to the higer- 
                order-function is rendered. The "pass through" concept I 
                discuss is shown here. Notice how all props from the 
                OuterComponent are passed through to the InnerComponent (ie 
                ContactList) 
                */
                return <InnerComponent { ...this.props } />
            }
        }
    }
    
        5
  •  0
  •   Samiksha Jagtap    8 年前

    我改变了传递和访问数据的方式。我更改的代码如下-

    联系人列表组件代码

    import React, { Component } from 'react';
    import '../App.css';
    import Loader from './hoc/Loader.js';
    
    class ContactList extends Component {
      constructor(props) {
        super(props);
        this.state = {
        }
      }
    
      render() {
        return (
          <div className="App">
            {
              this.props.contacts.map((contact, index) => (
                <div key={index}>
                  <p>{contact.name}</p>
                </div>
              ))
            }
          </div>
        );
      }
    }
    
    export default Loader('contacts')(ContactList);
    

    加载器(高阶组件)的代码-

    import React, { Component } from 'react';
    import './Loader.css';
    
    const Loader = (propName) => (WrappedComponent) => {
        return class Loader extends Component {
            isEmpty(prop) {
                return (
                    prop === null ||
                    prop === undefined ||
                    (prop.hasOwnProperty('length') && prop.length === 0) ||
                    (prop.constructor === Object.keys(prop).length === 0)
                );
            }
            render() {
                return this.isEmpty(this.props[propName]) ? <div className="loader"></div> : <WrappedComponent {...this.props}/>
            }
        }
    }
    
    export default Loader;