From e05a9ec414ffa7e8a3a7df27140935fb4f9d355f Mon Sep 17 00:00:00 2001 From: mzabriskie Date: Wed, 21 Oct 2015 23:33:35 -0600 Subject: [PATCH] [fixed] Issue when conditionally rendering Tab/TabPanel closes #37 --- examples/conditional/app.js | 53 +++++++++++++++++++++++++++ examples/conditional/index.html | 8 ++++ lib/components/Tabs.js | 12 ++++++ lib/components/__tests__/Tabs-test.js | 20 ++++++++++ lib/helpers/childrenPropType.js | 12 ++++++ 5 files changed, 105 insertions(+) create mode 100644 examples/conditional/app.js create mode 100644 examples/conditional/index.html diff --git a/examples/conditional/app.js b/examples/conditional/app.js new file mode 100644 index 0000000000..505462bfee --- /dev/null +++ b/examples/conditional/app.js @@ -0,0 +1,53 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Tab, Tabs, TabList, TabPanel } from '../../lib/main'; + +const App = React.createClass({ + getInitialState() { + return { + showA: true, + showB: true, + showC: true + }; + }, + + handleCheckClicked(e) { + const state = {}; + state[e.target.name] = e.target.checked; + this.setState(state); + }, + + render() { + return ( +
+

+
+
+
+

+ + + { this.state.showA && Tab A } + { this.state.showB && Tab B } + { this.state.showC && Tab C } + + { this.state.showA && This is tab A } + { this.state.showB && This is tab B } + { this.state.showC && This is tab C } + +
+ ); + } +}); + +ReactDOM.render(, document.getElementById('example')); + diff --git a/examples/conditional/index.html b/examples/conditional/index.html new file mode 100644 index 0000000000..7c1f048bea --- /dev/null +++ b/examples/conditional/index.html @@ -0,0 +1,8 @@ + + +React Tabs + +
+ + + diff --git a/lib/components/Tabs.js b/lib/components/Tabs.js index c795407d0e..017d6c9ed9 100644 --- a/lib/components/Tabs.js +++ b/lib/components/Tabs.js @@ -214,6 +214,12 @@ module.exports = React.createClass({ // Map children to dynamically setup refs return React.Children.map(children, (child) => { + // null happens when conditionally rendering TabPanel/Tab + // see https://github.com/rackt/react-tabs/issues/37 + if (child === null) { + return null; + } + let result = null; // Clone TabList and Tab components to have refs @@ -222,6 +228,12 @@ module.exports = React.createClass({ result = cloneElement(child, { ref: 'tablist', children: React.Children.map(child.props.children, (tab) => { + // null happens when conditionally rendering TabPanel/Tab + // see https://github.com/rackt/react-tabs/issues/37 + if (tab === null) { + return null; + } + const ref = 'tabs-' + index; const id = tabIds[index]; const panelId = panelIds[index]; diff --git a/lib/components/__tests__/Tabs-test.js b/lib/components/__tests__/Tabs-test.js index b63e7419e5..61bec6cced 100644 --- a/lib/components/__tests__/Tabs-test.js +++ b/lib/components/__tests__/Tabs-test.js @@ -236,5 +236,25 @@ describe('react-tabs', function() { ok(!error); }); + + it('should gracefully render null', function() { + let error = false; + try { + TestUtils.renderIntoDocument( + + + Tab A + { false && Tab B } + + Content A + { false && Content B } + + ); + } catch (e) { + error = true; + } + + ok(!error); + }); }); }); diff --git a/lib/helpers/childrenPropType.js b/lib/helpers/childrenPropType.js index 6c5f21fe7d..4eac704c60 100644 --- a/lib/helpers/childrenPropType.js +++ b/lib/helpers/childrenPropType.js @@ -9,8 +9,20 @@ module.exports = function childrenPropTypes(props, propName) { const children = props[propName]; React.Children.forEach(children, (child) => { + // null happens when conditionally rendering TabPanel/Tab + // see https://github.com/rackt/react-tabs/issues/37 + if (child === null) { + return; + } + if (child.type === TabList) { React.Children.forEach(child.props.children, (c) => { + // null happens when conditionally rendering TabPanel/Tab + // see https://github.com/rackt/react-tabs/issues/37 + if (c === null) { + return; + } + if (c.type === Tab) { tabsCount++; } else {