从React.11.2升级到.12.2,直接调用React组件

Upgrading from React .11.2 to .12.2 calling a react component directly

本文关键字:React 调用 组件 2升      更新时间:2023-09-26

所以我正在将React版本从.11.2更新到.12.2。我看到很多关于calling a React component directly. Use a factory or JSX instead. 的警告

下面是我的一个react类,它声称直接调用react组件:

function(
    Tab, //single tab (with content)
    TabGroup, //group of tabs that can be collapsed, accordion-style
    TabList //TabList module, independent of Tabpanel
) {
    /**
     * What goes between the parent and child values when passed to Tabs
     * @example
     * <TabGroup val="p">
     *     <Tab val="c"></Tab>
     * </TabGroup>
     * //the child tab will have an actual value of 'p' + PARENT_CHILD_DELIMITER + 'c', or 'p__c'
     * @const
     * @type {String}
     */
    var PARENT_CHILD_DELIMITER = '__';
    var SUBITEM_PREFIX = function() {
        //TODO: Use <Icon> module
        return ''u21B3 ';
    };
    var oneTabItem = function(tab) {
        return {
            text: tab.props.text || tab.props.val,
            val: tab.props.val,
            data: {
                type: 'tab'
            }
        };
    };
    /**
     * Returns an array of config objects, to be passed along to Tabs module,
     * generated off of a single TabGroup and its children.
     * @param  {TabGroup} tg The TabGroup in question
     * @return {Object[]}
     */
    var tabGroupItems = function(tg) {
        /**
         * The config for the collapsable group tab
         * @type {Object}
         */
        var groupItem = oneTabItem(tg);
        //add the down arrow
        //TODO: Use <Icon> module
        // groupItem.text = [
        //     ''u25BC ',
        //     groupItem.text
        // ];
        groupItem.data.type = 'group';
        groupItem.data.state = 'open';
        //Build up an array of configs for all the relevant tabs for this TabGroup
        return [groupItem].concat(_.values(React.Children.map(tg.props.children, function(child) {
            var tabItem = oneTabItem(child);
            tabItem.val = groupItem.val + PARENT_CHILD_DELIMITER + tabItem.val;
            tabItem.text = [
                SUBITEM_PREFIX(),
                tabItem.text
            ];
            return tabItem;
        })));
    };
    var tabsRef = 'tab-list';
    var Tabpanel = React.createClass({
        getInitialState: function() {
            var tabGroupsChildren = this.tabGroupsChildren(),
                selectedTabVal = this.props.initialSelected;
            if (selectedTabVal in tabGroupsChildren) {
                selectedTabVal = tabGroupsChildren[selectedTabVal][0];
            }
            return {
                selectedTabVal: selectedTabVal
            };
        },
        getDefaultProps: function() {
            return {
                initialSelected: null
            };
        },
        /**
         * Returns a dictionary of each TabGroup's value to an array of its children's values.
         * This is useful for deciding what should actually be selected after clicking on a
         * parent tab (since TabGroups don't have any content of their own)
         * @example
         * Given:
         * ```xml
         * <TabGroup val="g1">
         *     <Tab val="a"></Tab>
         *     <Tab val="b"></Tab>
         * </TabGroup>
         * <TabGroup val="g2">
         *     <Tab val="a"></Tab>
         * </TabGroup>
         * ```
         * Returns:
         * ```javascript
         * {
         *     "g1": ["g1__a", "g1__b"],
         *     "g2": ["g2__a"]
         * }
         * ```
         * @return {Object.<string, Array.<string>>}
         */
        tabGroupsChildren: function() {
            var self = this;
            var set = {};
            React.Children.forEach(self.props.children, function(child) {
                if (child instanceof TabGroup) {
                    //store array of children vals
                    set[child.props.val] = _.values(React.Children.map(child.props.children,
                        function(grandchild) {
                            return child.props.val + PARENT_CHILD_DELIMITER + grandchild.props.val;
                        }
                    ));
                }
            });
            return set;
        },
        /**
         * Returns a dictionary translating a tab's value to its content.
         * Useful for determining which content should be shown.
         * @return {Object}
         */
        valToContent: function() {
            var self = this;
            var valToContent = {};
            React.Children.forEach(self.props.children, function(child) {
                if (child instanceof Tab) {
                    valToContent[child.props.val] = child.props.children;
                } else {
                    React.Children.forEach(child.props.children, function(grandchild) {
                        valToContent[child.props.val + PARENT_CHILD_DELIMITER + grandchild.props.val] =
                            grandchild.props.children;
                    });
                }
            });
            return valToContent;
        },
        /**
         * Triggered when the selected tab is changed.
         * Sets it to the first child if a TabGroup was selected.
         * @param  {string} newVal The val of the clicked tab
         */
        tabChanged: function(newVal) {
            var self = this;
            var tabGroupsChildren = self.tabGroupsChildren();
            if (newVal in tabGroupsChildren && tabGroupsChildren[newVal].length) {
                //when selecting a group, select the first item in that group
                self.setState({selectedTabVal: tabGroupsChildren[newVal][0]});
                //make sure the state of the tabs module also gets updated
                //(using string key so it doesn't get eaten by Closure)
                self.refs[tabsRef].setState({val: tabGroupsChildren[newVal][0]});
            } else {
                self.setState({selectedTabVal: newVal});
            }
        },
        tabItems: function() {
            var self = this;
            var tabItem;
            /*
             * Lots of stuff going on here...
             *
             * First of all, flatten is converting a React object into a regular array
             * (since the react object is typically {'.$1': Object, '.$2': Object})
             *
             * From there, we're mapping each tab to the appropriately formatted
             * dictionary that can be passed along to the Tabs module,
             * using the above oneTabItem and tabGroupItems functions
             *
             * We only actually want all of the tabGroupItems if
             * the TabGroup is active (expanded). Otherwise, we can just
             * use a regular oneTabItem config, but with a closed arrow
             */
            return _.flatten(_.values(React.Children.map(self.props.children, function(child) {
                if (child instanceof Tab) {
                    return oneTabItem(child);
                } else {
                    if (self.openGroup() === child.props.val) {
                        return tabGroupItems(child);
                    } else {
                        //closed TabGroup
                        //add the right arrow
                        //TODO: Use <Icon> module
                        tabItem = oneTabItem(child);
                        // tabItem.text = [
                        //     ''u25B6 ',
                        //     tabItem.text
                        // ];
                        tabItem.data.type = 'group';
                        tabItem.data.state = 'closed';
                        return tabItem;
                    }
                }
            }, self)));
        },
        activeTabContent: function() {
            return this.valToContent()[this.state.selectedTabVal] || <div></div>;
        },
        openGroup: function() {
            var delimiterIndex;
            if (this.state.selectedTabVal == null) {
                return '';
            }
            delimiterIndex = this.state.selectedTabVal.indexOf(PARENT_CHILD_DELIMITER);
            if (delimiterIndex === -1) {
                return '';
            } else {
                return this.state.selectedTabVal.substr(0, delimiterIndex);
            }
        },
        className: function() {
            var self = this;
            return 'tabpanel' +
                (self.props.className ? ' ' + self.props.className : '');
        },
        render: function() {
            var self = this;
            return <div className={self.className()}>
                    <TabList
                        ref={tabsRef}
                        items={self.tabItems()}
                        initialSelected={self.state.selectedTabVal}
                        direction="column"
                        onChange={self.tabChanged}
                        tabClass="tabpanel-tab" />
                    <div className="content">
                        {self.activeTabContent()}
                    </div>
                </div>;
        }
    });
    return Tabpanel;

我认为问题发生在以下位置之一:

tabGroupsChildren: function() {
    var self = this;
    var set = {};
    React.Children.forEach(self.props.children, function(child) {
        if (child instanceof TabGroup) {
            //store array of children vals
            set[child.props.val] = _.values(React.Children.map(child.props.children,
                function(grandchild) {
                    return child.props.val + PARENT_CHILD_DELIMITER + grandchild.props.val;
                }
            ));
        }
    });
    return set;
},
/**
 * Returns a dictionary translating a tab's value to its content.
 * Useful for determining which content should be shown.
 * @return {Object}
 */
valToContent: function() {
    var self = this;
    var valToContent = {};
    React.Children.forEach(self.props.children, function(child) {
        if (child instanceof Tab) {
            valToContent[child.props.val] = child.props.children;
        } else {
            React.Children.forEach(child.props.children, function(grandchild) {
                valToContent[child.props.val + PARENT_CHILD_DELIMITER + grandchild.props.val] =
                    grandchild.props.children;
            });
        }
    });
    return valToContent;
}

或者在渲染中:

render: function() {
    var self = this;
    return <div className={self.className()}>
            <TabList
                ref={tabsRef}
                items={self.tabItems()}
                initialSelected={self.state.selectedTabVal}
                direction="column"
                onChange={self.tabChanged}
                tabClass="tabpanel-tab" />
            <div className="content">
                {self.activeTabContent()}
            </div>
        </div>;
}

有什么想法吗?

根据对类似问题的回答,我认为最终的return Tabpanel;就是问题所在(假设调用代码然后继续使用Tabpanel作为函数)

相反,您可能需要尝试return React.createFactory(Tabpanel);