簡體   English   中英

React:是否可以在容器組件內調用更高階的組件?

[英]React: Is it possible to call a higher-order component within a container component?

在我的代碼庫中,我有一個高階組件(HOC),可用於將所有輸入驗證功能添加到給定組件。 在像這樣的已定義組件上使用時,它效果很好。

let NameInput = React.createClass({
    render() {
        return (
            <div>
                <label htmlFor="name-input">Name</label>
                <input name="name-input" />
            </div>
        );
    }
});

let NameInput = addInputValidation(NameInput);

module.exports = NameInput;

但是我現在需要基於服務器上的數組定義一系列輸入。 像這樣

let TestApp = React.createClass({
    render() {
        // Pretend the names array came from the server and is actually an array of objects.
        let names = ['First name', 'Middle name', 'Last name'];

        // Map over our names array in hopes of ending up with an array of input elements
        let nameComponents = names.map((name, index) => {
            let componentToRender = (
                    <div key={index}>
                        <label htmlFor={name}>{name}</label>
                        <input name={name} />
                    </div>
            );

            // Here is where I'd like to be able to use an HOC to wrap my name inputs with validation functions and stuff
            componentToRender = addInputValidation(componentToRender);

            return componentToRender;
        })


        return (
            <div>
                <p>Enter some names:</p>
                {nameComponents}
            </div>
        );
    }
})

let addInputValidation = function(Component) {
    let hoc = React.createClass({
        getInitialState() {
            return {
                isValid: false
            };
        },
        render() {
            return (
                <div>
                    <Component {...this.props} />
                    {this.state.isValid ? null : <p style={{color: "red"}}>Error!!!!</p>}
                </div>
            );
        }
    });

    return hoc;
}

module.exports = TestApp;

當您嘗試呈現從另一個組件內部調用HOC的結果時,React不喜歡它。

我認為這與我的componentToRender實際上不是一個React組件無關。

所以我的問題是

為什么不能從另一個組件中調用HOC?

有沒有一種方法可以在數組的每個元素上調用HOC?

這是一個可能有用的jsfiddle: https ://jsfiddle.net/zt50r0wu/

編輯以澄清某些事情:

我映射到的數組實際上是描述輸入細節的對象數組。 包括輸入類型(選擇,復選框,文本等)。

另外,我的addInputValidation HOC實際上接受的參數不僅僅是組件。 它需要一個將從Redux存儲拉出的存儲索引數組,以用於驗證。 這些存儲索引來自描述輸入的對象數組中的信息。 可以訪問此潛在動態數組是我希望能夠在React生命周期內調用HOC的原因。

因此,在我的輸入數組上進行映射可能看起來像這樣……

let Select = require('components/presentational-form/select');
let Text = require('components/presentational-form/select');
let CheckboxGroup = require('components/presentational-form/select');
let TestApp = React.createClass({
    render() {
        // Pretend the inputs array came from the server
        let inputs = [{...}, {...}, {...}];
        // Map over our inputs array in hopes of ending up with an array of input objects
        let inputComponents = inputs.map((input, index) => {    
            let componentToRender = '';

            if (input.type === 'select') {
                componentToRender = <Select labelText={input.label} options={input.options} />;
            } else if (input.type === 'text') {
                componentToRender = <Text labelText={input.label} />;
            } else if (input.type === 'checkbox') {
                componentToRender = <CheckboxGroup labelText={input.label} options={input.options} />;
            }

            // Here is where I'd like to be able to use an HOC to wrap my name inputs with validation functions and stuff
            componentToRender = addInputValidation(componentToRender, input.validationIndexes);

            return componentToRender;
        })


        return (
            <div>
                <p>Enter some names:</p>
                {inputComponents}
            </div>
        );
    }
})

關於您的編輯:問題仍然在於,您正在從.map回調中返回組件而不是元素。 但這可以通過更改輕松地解決

return componentToRender;

return React.createElement(componentToRender);

您的代碼中的問題是:

  • addInputValidation期望傳遞一個組件,但是您傳遞給它一個元素<div /> )。
  • JSX希望傳遞一個(數組)元素,但是您正在傳遞它一個組件數組。

看來解決問題的最簡單方法是創建一個通用的Input組件,該組件接受名稱和值作為prop:

let Input = React.createClass({
    render() {
        return (
            <div>
                <label htmlFor={this.props.name}>{this.props.name}</label>
                <input name={this.props.name} />
            </div>
        );
    }
});

module.exports = addInputValidation(Input);

用作

let nameComponents = names.map((name, index) => <Input key={index} name={name} />);

我認為您要克服的是組件與元素之間的區別。 我發現將組件視為功能,並將元素視為該功能的結果很有幫助。 因此,您真正要做的就是有條件地選擇三個不同功能之一,將其傳遞一些參數,然后顯示結果。 我相信您想要這樣的東西:

(順便說一句,可以清理一下,只是嘗試盡可能地保留您的代碼結構)

let Select = require('components/presentational-form/select');
let Text = require('components/presentational-form/select');
let CheckboxGroup = require('components/presentational-form/select');
let TestApp = React.createClass({
    render() {
        // Pretend the inputs array came from the server
        let inputs = [{...}, {...}, {...}];
        // Map over our inputs array in hopes of ending up with an array of input objects
        let inputComponents = inputs.map((input, index) => {    
            let ComponentToRender;
            let props;            

            if (input.type === 'select') {
                ComponentToRender = addInputValidation(Select);
                props = { labelText: input.label, options: input.options };
            } else if (input.type === 'text') {
                ComponentToRender = addInputValidation(Text);
                props = { labelText: input.label };
            } else if (input.type === 'checkbox') {
                ComponentToRender = addInputValidation(CheckboxGroup);
                props = { labelText: input.label, options: input.options };
            }

            let element = <ComponentToRender {...props} />;

            return element;
        })


        return (
            <div>
                <p>Enter some names:</p>
                {inputComponents}
            </div>
        );
    }
})

是的,有一種方法。 但是,HOC通常是處理驗證的一種痛苦方式。

基於ValueLink模式有另一種驗證方法

只需將結果代碼與高階組件方法進行比較即可。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM