所以我正在将我们的React版本从.11.2更新为.12.2。我看到很多关于calling a React component directly. Use a factory or JSX instead.
这是我声称直接调用反应组件的反应类之一:
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>;
}
有什么想法吗?
答案 0 :(得分:0)
根据similar question的答案,我认为最终的return Tabpanel;
是问题(假设调用代码继续使用Tabpanel作为函数。)
相反,您可能想尝试return React.createFactory(Tabpanel);