Multiple ReactDOM.render calls with shared router context - javascript

I got two React components rendered like this.
ReactDOM.render(
<Router history={ browserHistory }>
<Route path='/items' component={ App }>
<IndexRoute component={ Home } />
<Route path='/items/:id' component={ Details } />
</Route>
</Router>,
document.getElementById('app')
);
And the second one, which is a sidebar.
ReactDOM.render(
<Sidebar />,
document.getElementById('sidebar')
);
I'd like to use the Link helper from react-router in the Sidebar component. However, I get the following error: "Uncaught Invariant Violation: Links rendered outside of a router context cannot navigate.". Which makes sense, because the sidebar is not within the router context like the first seen above.
Is there a way to share the router context with the sidebar?
I'd like to change the sidebar layout based on the route (and access the router object in this.props properly) and use Link as it should be.
I don't want to work my way around hacky approaches like history.pushState, or parsing location.path to change the sidebar's layout according to the corresponding route of items.

You should be able to just render your sidebar in its own <Router>. The important thing is that they share the same history instance (in this case, browserHistory).
When a <Router> mounts, it adds a listener to its history instance. When a history instance receives a new location, it notifies all of its listeners.
ReactDOM.render((
<Router history={browserHistory}>
<Route component={Sidebar} />
</Router>
) document.getElementById('sidebar')

Related

How to tell a NavLink in a component with multiple routers to change the route of only in one of them?

Im working on a react project with react-router-dom.
my root App component is a <Router> wrapping a <Switch>, that has 2 <Routes>:
<Router>
<Switch>
<Route to="/" component={Intro}>
<Route to="/dashboard/home" component={Dashboard}>
</Switch>
</Router>
Dashboard Component has its own inner <Router>.
class Dashboard extends Component {
render(){
<div>
<Menu>
<Router>
<Switch>
<Route to="/dashboard/home">
<Route to="/dashboard/about">
<Route to="/dashboard/contact">
</Switch>
<Router>
</div>
}
}
<Menu> has a <NavLink> to each of the routes, and has an extra <NavLink> that suppose to take you back to the Intro component/page.
<Intro>is not part of the dashboard's view. it's a separate page.
My Problem:
my "Back to Intro" link, <NavLink to="/">, changes the route inside the Dashboard Router, but I need it to change the route of the outer router.
what is the right way of arranging my routers in order to have a path back to the outer one ?
This is the project screen navigation concept:
Intro <---> Dashboard --> different content

React BrowserRouter - how to programmatically navigate to different routes?

I currently have this in my app.js file:
<BrowserRouter>
<div>
<Switch>
<Route exact path="/" component={CompOne}/>
<Route path="/two" component={CompTwo} />
</Switch>
</div>
</BrowserRouter>
In my CompOne, I want to programmatically navigate to CompTwo. I know I can use window.location to navigate to the /two path, but I would like to pass in some props to CompTwo.
How would I go about programmatically navigating from CompOne to CompTwo while passing in props?
One of the ways to do it is to make use of history.push() property so if you want to navigate to CompTwo you can do something like this inside CompOne :
this.props.history.push('/CompTwo');

Hide App Elements React

I have an <App/> component which renders for any page on my site:
const App = () => (
<div>
<Header />
<Main />
<Footer />
<Subfooter />
<SubfooterLegal />
</div>
)
export default App;
The problem I'm having now is that I have a Component (page) which doesn't include any of the components within <App /> aside from <Main /> (which is the router).
I'm puzzled on how to do this, since App.js is the parent component of all components. My only idea of how to do this (possibly) is that when a user clicks a <Link /> to the aforementioned component, I could add setState (maybe?) to App.js and change it to something like hideAppComponents = true and then hide the appropriate components. I know that in this case I would have to make <App /> extends Component since it would then be stateful.
Are there any suggested approaches for a use case like this?
As far as answering your specific question: Yes, adding state to your App and then rendering differently depending on the page would work.
However, a small refactoring of your components would make your problem easier.
In my opinion, a good use of <app> within the context of routing is to just use it to reference which route the user will be on.
<app>
<main>
<Switch>
<Route exact path='/' component={Home}/>
<Route exact path='/about' component={AboutUs}/>
<Route path='/somePageWithoutAFooter' component={CoolPage}/>
</Switch>
</main>
</app>
Now, you have set just a very set of minimal constraints from your top-level app. Depending on the route, you will render a specific child component. So this solves your direct problem. Now you can have CoolPage be its own custom thing, but then the Home page can do something else.
So far, so good. However lets say that both Home and AboutUs have the same basic template of the header and the subfooter that you've been talking about. It would be unfortunate for both of these components to have to describe this architecture inside the render. Instead, you could make a container component like this:
class MyLayout extends Component {
render() {
<div>
<Header />
{this.props.children}
<Footer />
<Subfooter />
<SubfooterLegal />
</div>
}
}
And this component can be used like this:
<MyLayout><Home></MyLayout>
So now, all you need to do is to wrap all of your normal pages in a MyLayout. This can either be done in the app itself, or in a child if it gets more complicated.
Edit: This example uses react-router since this post was tagged with it. You can follow the same principles without using the router if you want. It just makes the <Route> stuff easier to manage.
the only possible solution i can think other than your solution is to use loaction prop. Below is the sample code you can try.
import STORE from './store/STORE';
import {Provider} from 'react-redux';
import {Route, Router} from 'react-router-dom';
import createHashHistory from 'history/createHashHistory';
const history = createHashHistory();
render(
<Provider store={STORE}>
<Router history={history}>
<Route path="/" component={App}/>
</Router>
</Provider>, document.getElementById('app')
);
const App = (location) => (
location.pathname.includes("error") ?
<div>
<Main />
</div> :
<div>
<Header />
<Main />
<Footer />
<Subfooter />
<SubfooterLegal />
</div>
)
export default App;

Basic way to handle login with React

I'm working on a client-side app using create-react-app. The application renders a login component with a basic form and I want to load another component (which will be the main application) on successful login.
The validation and the login logic is not the issue at the moment because first I'm trying to figure out a simple way to dismount the login component and load another component on the submit event.
class Login extends Component {
handleLogin(){
// trigger to load Main.js
}
render() {
return (
// form elements here
<div className="submit">
<input className="button-signin" value="Sign In" type="submit"
onClick={this.handleLogin}/>
</div>
);
}
}
What would be the easiest way to switch to another component (which I called Main.js in this example) on submit event?
Have you tried using React router? It makes really easy to define routes and assign a Component to each of them. Then you can also establish conditions for accessing each route. There is an example in the official docs that seems to match your requirements.
<Router history={withExampleBasename(browserHistory, __dirname)}>
<Route path="/" component={App}>
<Route path="login" component={Login} />
<Route path="logout" component={Logout} />
<Route path="about" component={About} />
<Route path="dashboard" component={Dashboard} onEnter={requireAuth} />
</Route>
The method requireAuth will be checked each time you try to access the route dashboard (which will show the component Dashboard). If you are using token-based authentication, you might have a token stored in the localStorage and check if it's present in requireAuth.
Your method handleLogin would call the backend, log the user in (store the token in localStorage if that's how the login is handled) and then redirect to the dashboard route.

multi tabbed javascript application with URL support using ReactJS

I am designing a multi-tabbed or multi-paged javascript web application that allows the URL to change depending on which tab you selected.
The best example I have seen is done by Zendesk
By calling it multi-tabbed, am I describing it correctly?
The tabs can be closed or opened depending on what is clicked.
How to create something like this using ReactJS? If there is a good tutorial, I am also happy to read through it.
This can easily be done with react router. If you are not familiar with react router go to the react router github page and check out the tutorials and docs. Here's an example of what it may look like to get you going.
Routes
<Route path="/" component={Application}>
<IndexRoute component={Home}/>
<Route path="tabs" component={TabLayout}>
<Route path="1" component={Tab1} />
<Route path="2" component={Tab2} />
</Route>
<Route path="about" component={About}/>
<Route path="*" component={NotFound} isNotFound/>
</Route>
Tab Layout
/* This is the layout for your tabs. Using react router to link to different tabs.
When the route changes props.children will be updated to reflect the current
route. You can add active classes to your tabs. Reference the react-router docs to
see how to do that
*/
import {Link} from 'react-router';
const TabLayout = props => {
return (
<section className="tab-container">
<div className="tabs">
<Link to="/tabs/1">Tab 1</Link>
<Link to="/tabs/2">Tab 2</Link>
</div>
<div className="content">
{props.children}
</div>
</section>
);
};
Tab 1 and tab 2 look like this
// Tab1 and Tab2 are just react components. For simplicity I am just using
// a stateless component.
const Tab1 = props => {
return (
<h1>Tab 1</h1>
);
};

Categories

Resources