Switch between components inside of an already routed component in react - javascript

I have used react-router to switch between 2 pages from the navbar. One of the pages is Home component. Now I have 3 columns as components in the homepage. Left column, middle column, and right column. By a button in the left column, I want to switch between two components in the mid column of the homepage.
function App() {
return (
<div className="App">
<Router>
<Navbar/>
<Switch>
<Route exact path="/">
<Home/>
</Route>
<Route path="/FAQ">
<FAQ/>
</Route>
</Switch>
</Router>
</div>
);
}
At home components ->
class Home extends Component {
render() {
return (
<div className={style.homeFlex}>
<LeftContainer/>
**<MidContainer/>**
**<AnotherMid/>**
<RightContainer/>
</div>
</div>
)
}
}
export default Home;
From a button inside LeftContainer, I want to switch between MidContainer and AnotherMid.
How can I use the router inside of an already routed component Linked from a sibling component? If there is a better way other than using the router to achieve the same, please share that also.

You don't need a route in this situation. You can use a state to render different components in your Home component.
Suppose your LeftContainer component looks like this:
class LeftContainer extends React.Component {
render() {
return (
<div>
<button onclick={() => this.props.handleSwitchComponent()}>
click here to change component
</button>
</div>
);
}
}
You'll need to pass a function through props, then you can use this component in Home component like this:
class Home extends Component {
state = { IsMidContainerVisible: true }
handleSwitchComponent = () => {
this.setState(({ IsMidContainerVisible }) => ({
IsMidContainerVisible: !IsMidContainerVisible;
}));
};
render() {
return (
<div className={style.homeFlex}>
<LeftContainer handleSwitchComponent={this.handleSwitchComponent} />
{/* Now here we need to specify when we want to show components */}
{this.state.IsMidContainerVisible ? <MidContainer /> : <AnotherMid />}
<RightContainer />
</div>
);
}
}
export default Home;

Related

How can i use the same design with different data different pages in reactjs

I have a component called home pages where navbar i using i like use this same navber with my another component called shop.js with different data
This is the home component
const Home = () => {
return (
<React.Fragment>
<Header/>
</React.Fragment>
);
};
This is the header component
const Header = () => {
return (
<header>
<TopModal/>
<Navbar/>
<HeroSlider/>
</header>
);
};
This is the Shop.js components
export default function Shop() {
return (
<React.Fragment>
{/*this component coming from home component*/}
<Header/>
</React.Fragment>
)
}
I want to change the navbar value in shop.js?
make a separate component of the navbar and add the navbar component in the app.js file which will add the navbar to all files or add the navbar component to other component files in which you want the navbar and use props to change the button or data of the navbar
You can use the children property of the Header component to pass your own components:
const Header = ({children}) => {
let navbar = Navbar
if (children.length) {
navbar = children[0]
}
return (
<header>
<TopModal/>
{navbar}
<HeroSlider/>
</header>
);
};
Your Home component will be the same, while your Shop instead:
export default function Shop() {
return (
<React.Fragment>
<Header>
<ShopNavbar/>
</Header>
</React.Fragment>
)
}

React pass object by routing?

What I want to do is set routing to my object. For example:
I set routing for:
http://localhost:3000/projects
It displays all my projects list (it works pretty ok)
Then I want to choose project and see details, but it doesn't work properly:
http://localhost:3000/projects/3
How it looks like:
When I click to Details button, it sends me to /projects:id but I get an error, that items in project are undefined.
My code. I store all routing in main App.js file:
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<div>
<Route exact path="/projects" component={ProjectsList} />
<Route exact path="/projects/:id" component={ProjectDetails} />
</div>
</BrowserRouter>
</div>
);
}
}
export default App;
I have ProjectsList.js component (i will include code of it if needed), in ProjectsList.js i have listgroup with Project.js that looks like this:
class Project extends Component {
render() {
return (
<ButtonToolbar>
<ListGroupItem>{this.props.project.name</ListGroupItem>
<Link to={`/projects/${this.props.project.id}`}>
<Button>Details</Button>
</Link>
</ButtonToolbar>
);
}
}
export default Project;
By Link to my browser pass me to proper URL (projects/2... etc) but i dont know how to pass object of project to ProjectDetails.js component. Code of it below:
class ProjectDetails extends Component {
render() {
return <li>{this.props.project.description}</li>;
}
}
export default ProjectDetails;
Could you tell me, how to pass object of project by Link to into ProjectDetails.js? For now, i get description as undefined (its obviouse because i pass nothing to component with details).
Use the render method in your route and pass the props.
<Route exact path="/projects/:id" render={() => (
<ProjectDetails
project = {project}
/>
)}/>
You need to use mapStateToProps here. and wrap your component in the conncet from react-redux.
It should be like:
import {connect} from 'react-redux';
class ProjectDetails extends Component {
render() {
return <li>{this.props.project.description}</li>;
}
}
function mapStateToProps(state, ownProps){
const projectInstance = DATA //the Data you are getting or fetching from the ID.
return { project : projectInstance }
}
export default connect((mapStateToProps)(ProjectDetails))
This is what it will look like..!!
class Project extends Component {
render() {
return (
<ButtonToolbar>
<ListGroupItem>{this.props.project.name</ListGroupItem>
<Link to={`/projects/${this.props.project.id}`}>
<Button>Details</Button>
</Link>
</ButtonToolbar>
);
}
}
function mapStateToProps(state, ownProps){
return { project : { id: ownProps.params.id } }
}
export default connect((mapStateToProps)(Project))

Passing callback to children, to update a different child

I am trying to create a Navbar (component), which changes slightly when a user logs in in a SignIn component. So, my app looks like this:
I have a state in App, with authenticated set to false as default. I then have a function, updatedAuthenticationEvent, which sets the value of the app state.
Ihave a NavBar component, which I pass in the value of Authenticated. The idea is that I change something on the navbar, if authenticated. That would be, dont show "Signin" and rather show "Sign Out". So when I sign in on my sign in component, the navbar changes.
I then have a few routes in my app, one of which is my Signin, which I attempt to pass my function to, as a callback.
export default class App extends React.Component {
constructor(props)
{
super(props);
this.state = {
authenticated: false
}
}
updatedAuthenticationEvent(isAthenticated)
{
console.log('Called!');
this.setState({authenticated: isAthenticated});
}
render() {
return (
<div>
<Router>
<div>
<Navbar authenticated={this.state.authenticated} />
<Route exact path='/' component={Home} />
<Route path="/login" component={Login} changeState={this.updatedAuthenticationEvent} />
</div>
</Router>
<Footer />
</div>
)
}
}
My SignIn component, actually wraps my sign in content.
But for now, I'm just trying to make something work.
So for now, all I am doing is that when the sign in component loads, set the Authenticated to true.
My goal though is to pass that prop to my LoginBox, which has all the logic, and my actual sign in method. But for now, I want this to work.
export default class SignIn extends Component {
constructor(props)
{
super(props);
}
componentWillMount()
{
this.props.changeState(true);
}
render() {
return (
<div className="row justify-content-md-center">
<div className="col-lg-4">
<LoginBox changeState={this.props.changeState} />
</div>
</div>
)
}
}
I get the error:
TypeError: this.props.changeState is not a function
What do I need to change to achieve this? Signin box event, should effect the Navbar.
well, I will not recommend this, but here it is,
use the render prop from Router, so you can pass the callback for changeState directly
<Route path="/login" render={(props) => <Login {...props} changeState={this.updatedAuthenticationEvent} />
then I would recommend change componentWillMount for componentDidMount in your Login Component
and finally
Use an arrow function for your updatedAuthenticationEvent callback like
updatedAuthenticationEvent = (isAthenticated) => {
....
}
So you do not have context problems when executing changeState
working demo

How to link to current page with different param in react router?

Let's say I have the following routes set up (just an example, actual routes aren't this messy):
<Router>
<Switch>
<Route path="/app/fun/:userid/profile" component={Profile} exact/>
<Route path="/photos/:userid" component={Photos} exact/>
<Route path="/:userid/contact" component={Contact} exact/>
</Switch>
</Router>
From ANY of the pages above, how can I link to the SAME page, but with a different userid?
eg:
/**
* Shared component that's rendered by Profile, Photos and Contact
*/
class SharedComponent extends React.Component {
render() {
const bobId = 423423432;
return (
<div>
<Link to={/* what to put here? */}>
Redirect to the same page but with Bob's userid
</Link>
</div>
);
}
}
export default withRouter(SharedComponent);
Note: using react router v4
Actually, I found a way to do this. Not sure if it's the best way, but it works:
/**
* Shared component that's rendered by Profile, Photos and Contact
*/
class SharedComponent extends React.Component {
render() {
const { location, match } = this.props;
const bobId = 423423432;
const bobUrl = location.pathname.replace(match.params.userid, bobId);
return (
<div>
<Link to={bobUrl}>
Redirect to the same page but with Bob's userid
</Link>
</div>
);
}
}
export default withRouter(SharedComponent);
Essentially, I'm taking the current url (location.pathname) and replacing the current userid (match.params.userid) with the new id (bobId)
Pass userId with path props to shared component like below,
class Profile extends React.Component {
render() {
const bobId = 423423432; // Pass bobId with path from parent to child
return (
<SharedComponent path={"/stuff1/stuff2/`${bobId}`/profile"} />
);
}
}
class SharedComponent extends React.Component {
render() {
return (
<div>
<Link to={this.props.path}>
Redirect to the same page but with Bob's userid
</Link>
</div>
);
}
}
export default withRouter(SharedComponent);

How to render a nested component with react-router

This is a noob question. I'm developing a universal react application using react-isomorphic-starterkit boilerplate (https://github.com/RickWong/react-isomorphic-starterkit). I would create a "fixed" sidebar on the left that contains links to the other pages rendered on a child of the main container on the right. Here's my code:
routes.js
module.exports = (
<Router history={browserHistory}>
<Route path="/" component={Main}>
<Route path='/inbox' component={Inbox} />
</Route>
</Router>
);
Main.js
export default class Main extends React.Component {
constructor(props, context){
super(props,context);
console.log('Main props', props);
console.log('Main context', props);
}
/**
* componentWillMount() runs on server and client.
*/
componentWillMount () {
if (__SERVER__) {
console.log("Hello server");
}
if (__CLIENT__) {
console.log("Hello client");
}
}
/**
* Runs on server and client.
*/
render () {
return (
<App/>
)
}
}
App.js
class App extends React.Component{
constructor(props, context) {
super(props, context);
console.log('App props ', props);
}
render(){
return (
<div>
<Sidebar/>
<RightContent />
</div>
)
}
}
RightContent.js
class RightContent extends React.Component{
render(){
return (
<div id="b" style={{backgroundColor:"#EEF0F4", width:"100%"}}>
<NavBar />
{this.props.children}
</div>
)
}
}
Problem is: Inbox component (a simple <div>) is not rendering when I click on the sidebar with <Link to="..."> tag. I don't know if the following thing is correct: as you can see, in App.js class constructor prints props variable...but the output is undefined. However, in Main.js props are printed correctly. react-router version is greater than 2. Could anyone help me?
You're not passing props down to App, so unless you use the location context, it won't have them.
You should do...
render () {
return (
<App {...this.props}/>
)
}
Then, you should have access to this.props.children in App to render the nested route(s). You'll need to specify that in RightContent too...
render(){
return (
<div>
<Sidebar/>
<RightContent>
{this.props.children}
</RightContent>
</div>
)
}
See the tutorial in the docs... https://github.com/reactjs/react-router/blob/master/docs/Introduction.md#with-react-router

Categories