Reputation: 1432
There is a HeaderComponent
and a BodyComponent
in my project.
This is the TabComponent
from the HeaderComponent
:
TabComponent
import React, {Component} from 'react'
import Context from '../../provider'
import {Nav, NavItem, NavLink} from 'reactstrap'
import {Redirect} from 'react-router-dom'
import classnames from 'classnames'
export default class TabComponent extends Component {
render() {
return (
<Context.Consumer>
{context => (
<Nav tabs color='primary'>
<NavItem>
<NavLink
className={classnames({ active: context.activeTab === '1' })}
onClick={() => { context.toggleTab('1'); }}
>
Home
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({ active: context.activeTab === '2' })}
onClick={() => { context.toggleTab('2'); }}
>
Popular
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({ active: context.activeTab === '3' })}
onClick={() => { context.toggleTab('3'); }}
>
All
</NavLink>
</NavItem>
</Nav>
)}
</Context.Consumer>
)
}
}
BodyComponent
import React, {Component} from 'react'
import Context from '../provider'
import SwitchTab from './OtherComponents/SwitchTab'
import { BrowserRouter, Route, Redirect } from "react-router-dom";
export default class BodyComponent extends Component {
render() {
return (
<Context.Consumer>
{context => {
return (
<React.Fragment>
<BrowserRouter>
<React.Fragment>
<Route exact path='/' render={() => <Redirect to='/home/' /> } />
<Route eaxt path='/home/' render={() => context.activetab='1'} />
<Route eaxt path='/popular/' render={() => context.activetab='2'} />
<Route eaxt path='/all/' render={() => context.activetab='3'} />
</React.Fragment>
</BrowserRouter>
<SwitchTab />
</React.Fragment>
)
}}
</Context.Consumer>
)
}
}
This is my provider.js which has the Context
import React, {Component} from 'react';
const Context = React.createContext();
class Provider extends Component {
state = {
loggedIn: false,
username: '',
password: '',
loginModalOpen: false,
signupModalOpen: false,
navbarOpen: false,
activeTab: '3',
toggleLoggedIn: () => {
this.setState({loggedIn: !this.state.loggedIn});
},
toggleLoginModal: () => {
this.setState({loginModalOpen: !this.state.loginModalOpen});
},
toggleSignupModal: () => {
this.setState({signupModalOpen: !this.state.signupModalOpen});
},
toggleNavbar: () => {
this.setState({navbarOpen: !this.state.navbarOpen})
},
toggleTab: (tab) => {
if(this.state.activeTab !== tab) {
this.setState({activeTab: tab});
}
}
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
}
export {Provider};
export default Context;
And, this is my SwitchTab
import React, {Component} from 'react'
import Context from "../../../provider";
import { Container, TabContent, TabPane } from "reactstrap";
import Home from '../../Content/Home'
import Popular from '../../Content/Popular'
import All from '../../Content/All'
export default class SwitchTab extends Component {
render() {
return (
<Context.Consumer>
{context => {
return (
<Container>
<TabContent activeTab={context.activeTab}>
<TabPane tabId="1">
<Home />
</TabPane>
<TabPane tabId="2">
<Popular />
</TabPane>
<TabPane tabId="3">
<All />
</TabPane>
</TabContent>
</Container>
)
}}
</Context.Consumer>
)
}
}
The functionality that I want to achieve is:
activeTab
from the
Context
and make SwitchTab
re-render so that home
tab gets
opened.The current working state is whenever I click on a tab, the content changes but the URL remains as /home/
. If the Change the URL to /popular/
or /all/
, it doesn't change the content.
Upvotes: 0
Views: 6312
Reputation: 281764
The error clearly states what is wrong with your problem, you need to wrap your Routes within a div
as a Router
accepts only one child element.
Also in order to set the state in Provider you need to use setState
or provide a handler
class Provider extends Component {
state = {
loggedIn: false,
username: '',
password: '',
loginModalOpen: false,
signupModalOpen: false,
navbarOpen: false,
activeTab: '3',
setActiveTab: (tab) => {
this.setState({activeTab: tab});
}
toggleLoggedIn: () => {
this.setState({loggedIn: !this.state.loggedIn});
},
toggleLoginModal: () => {
this.setState({loginModalOpen: !this.state.loginModalOpen});
},
toggleSignupModal: () => {
this.setState({signupModalOpen: !this.state.signupModalOpen});
},
toggleNavbar: () => {
this.setState({navbarOpen: !this.state.navbarOpen})
},
toggleTab: (tab) => {
if(this.state.activeTab !== tab) {
this.setState({activeTab: tab});
}
}
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
}
also since you can't set state in render directly, you would need to create a component that handles this case
class Handler extends React.Component {
componentDidMount() {
this.props.setActiveTab(this.props.activeTab);
}
render() {
return null;
}
}
and your Router config would look like
<BrowserRouter>
<div>
<Route exact path='/' render={() => <Redirect to='/home/' /> } />
<Route exact path='/home/' render={() => <Handler setActiveTab={setActiveTab} activeTab={'1'} />}/>
<Route exact path='/popular/' render={() => <Handler setActiveTab={setActiveTab} activeTab={'2'} />}/>
<Route exact path='/all/' render={() => <Handler setActiveTab={setActiveTab} activeTab={'3'} />}/>
</div>
</BrowserRouter>
Upvotes: 2