react-router-dom on the server - javascript

I did find out that I can't use when I'm rendering my app on the server. I would like to wrap my App in specified router depending on the situation - BrowserRouter on the CLient side and StaticRouter on server side. My App looks like this:
imports......
class App extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<BrowserRouter>
<div>
<Menu />
<main>
<Switch>
<Route exact path="/about" component = {About} />
<Route exact path="/admin" component = {BooksForm} />
<Route exact path="/cart" component = {Cart} />
<Route exact path="/" component = {BookList} />
</Switch>
<Footer />
</main>
</div>
</BrowserRouter>
);
}
componentDidMount(){
this.props.getCart();
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
getCart
}, dispatch)
}
export default connect(null, mapDispatchToProps)(App);
I tried to move my BrowserRouter ou of this component so my index.js would look like this:
imports....
const renderApp = () => (
<Provider store={createStoreWithMiddleware(reducers)}>
<BrowserRouter>
<App/>
</BrowserRouter>
</Provider>
)
const root = document.getElementById('app')
render(renderApp(), root)
So I would get ability to wrap my app in different routers. The problem is when I moved BrowserRouter out of my App component it stopped working. Clicking on links just does not work anymore. The url is changing but my app isn't rendering differnet components. How can I move router out of this component?

On the server, you'll wrap your app similar to this:
const routerContext = {};
const appComponent = (
<Provider store={store}>
<StaticRouter location={req.url} context={routerContext}>
<App />
</StaticRouter>
</Provider>
);
Where you pass react-router the location (from the url) as well as a context object.
The client side is like your example:
<Provider store={createStoreWithMiddleware(reducers)}>
<BrowserRouter>
<App/>
</BrowserRouter>
</Provider>

Related

React Router V4 - props not being passed to this.props.children from parent component

React.cloneElement is not passing props to child components when using react-router v4. I'm getting the history and location props. Just not getting any of the actions or props from mapStateToProps.
works fine when using react-router v3...only when i update version the props are not being passed.
class Main extends React.Component{
render(){
var clonedElements = React.cloneElement(this.props.children, this.props);
return(
<div>
<h1>
<Link className='headLine' to='/'><img src='https://i.imgur.com/DFkO2gb.png'/></Link>
<p className='disclosure'>....</p>
</h1>
{clonedElements}
</div>
)
}
}
const router = (
<Provider store={store}>
<Router history={history}>
<App>
<Switch>
<Route exact render={props => <CardsGrid {...props} /> }></Route>
<Route exact path='/view/:postId' component={Single}></Route>
</Switch>
</App>
</Router>
</Provider>
)
function mapStateToProps(state){
return {
posts: state.posts,
comments: state.comments
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators(actionCreators, dispatch);
}
const App = withRouter(connect(mapStateToProps, mapDispatchToProps)(Main));
export default App;
I'm expecting to see 2 props set by the initial state as props. I'm seeing none of those right now.

Cannot connect page by address directly

I am making my own blog now and using react with react-router-dom.
When I type url except '/' in address bar directly, I get Cannot GET /url error in chrome.
But localhost:8000/ is working properly.
ex) localhost:8000/favorite ==> Cannot GET /favorite
And clicking header and redirect is working. Only typing in address bar is not working.
My codes structure simplified below.
index.js
const rootElement = document.getElementById('root');
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
,
rootElement);
App.js
class App extends React.Component {
render(){
return (
<div>
<Header/>
<Main></Main>
</div>
);
}
}
export default App;
Main.js
const Main = () => (
<main>
<Switch>
<Route exact path='/' component={HomeContainer}/>
<Route path='/post' component={Post}/>
<Route path='/favorite' component={Favorite}/>
<Route path='/setting' component={Setting}/>
</Switch>
</main>
)
export default Main
header.js
<div>
<Menu.Item><Link to='/'><Icon onClick={this.clickMenu} name='home' data- name='home' size="large"/></Link></Menu.Item>
<Menu.Item><Link to='/post'><Icon onClick={this.clickMenu} name='list'data-name='list' size="large"/></Link></Menu.Item>
<Menu.Item><Link to='/favorite'><Icon onClick={this.clickMenu} name='favorite' data-name='favorite' size="large"/></Link></Menu.Item>
<Menu.Item><Link to='/setting'><Icon onClick={this.clickMenu} name='settings' data-name='settings'size="large"/>/Link></Menu.Item>
</div>

React router v4 not rendering component

I'm new to React and trying to follow a tutorial on how to set up the router. However when I run the app, the component does not render, and the HTML just says react-empty.
index.js:
ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById('root')
);
App.js:
const App = () => (
<div>
<Main />
</div>
)
export default App;
Main.js:
const Main = () => (
<div>
<main>
<h1>MAIN</h1>
<Route exact path="/" component={Home}/>
</main>
</div>
)
export default Main;
Home.js:
class Home extends Component {
constructor() {
super()
console.log('home component');
}
render() {
return (
<div>
<h1 className="wat">waaaat</h1>
</div>
)
}
}
export default Home;
Also, I can see the Route in the React plugin for chrome like so: http://imgur.com/a/LXuwC
EDIT:
It works if i put:
<Switch>
<Route path="/" component={Home}/>
</Switch>
directly in App.js instead of the Main element.

Defining routes in constructor

I have a component called Root which renders the Routes for my index.js
const store = configureStore();
ReactDOM.render(
<Root store={store} />,
document.getElementById('root'),
);
I need to do this because I am connecting Root to redux, this is due to root authorization with onEnter, and it needs to work with redux state.
So here is the Root:
class Root extends React.Component {
constructor(props) {
super(props);
// some stuff
}
requireAuthentication = (nextState, replace) => {
// some stuff for managing auth
};
render() {
const { store } = this.props;
return (
<div>
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={App}>
<Route component={Dashboard}>
<IndexRoute component={Home} onEnter={requireAuthentication}/>
</Route>
<Route path="login" component={Login} />
</Route>
</Router>
</Provider>
</div>
);
}
}
// some definitions for connecting Root to redux
export default connect(mapStateToProps, mapDispatchToProps)(Root);
Ok... this renders well, but I have a warning:
Warning: [react-router] You cannot change <Router routes>; it will be ignored
routes, also works fine... but I want to solve the warning. So... googling I found the problem an a possible solution: declare routes inside the constructor and pass it to Router via props.
My constructor I did this:
import React, { PropTypes } from 'react';
import { connect, Provider } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Router, browserHistory, Route, IndexRoute } from 'react-router';
import { loginActions } from '../actions';
import { App, Dashboard, Home, Login } from '../features';
import adalHandler from '../services/adal';
class Root extends React.Component {
constructor(props) {
super(props);
const routes = (
<Route path="/" component={App}>
<Route component={Dashboard}>
<IndexRoute component={Home} />
</Route>
<Route path="login" component={Login} />
</Route>
);
// some stuff
}
}
requireAuthentication = (nextState, replace) => {
// stuff
};
render() {
const { store } = this.props;
return (
<div>
<Provider store={store}>
<Router history={browserHistory} routes={this.routes} />
</Provider>
</div>
);
}
}
// stuff
export default connect(mapStateToProps, mapDispatchToProps)(Root);
but now, it is no rendering well.
How can I solve it?
Object this.routes isn't defined in the render method.
For example you can replace const routes = (...); in constructor with this.routes = (...); to make object accessible in the render method.

Redux & React-router : Provider bug

I'm starting new app using ReactJS. All the web env is quite new for me.
Anyway, I created an simple App, using react-router. Works perfectly :).
I tried to add Redux, and ... fail. I have no idea how use React-redux AND react-router.
Here's my input JS : index.js
class App extends React.Component{
render(){
return(
<div>
{routes}
</div>
);
}
}
ReactDOM.render(
<Provider store={store}> <App /> </Provider>,
document.getElementById('app')
);
Here's my route.js
export default (
<Router history={hashHistory}>
<Route path='/' component={Main}>
<IndexRoute component={Home} />
<Route path='playerOne' header="PlayerOne" component={PromptContainer} />
<Route path='playerTwo/:playerOne' header="PlayerTwo" component={PromptContainer} />
<Route path='battle' component={ConfirmBattleContainer} />
<Route path='results' component={ResultsContainer} />
<Route path='maninthemiddle' component={ManinthemiddleContainer} />
<Route path='button' component={ButtonContainer} />
</Route>
</Router>
);
and ofc my reducer.js
import reducer from './reducer.js'
import { createStore } from 'redux';
const store = createStore(reducer);
export default store;
And this is my error.
Uncaught Error: React.Children.only expected to receive a single React element > child
and my warning :
Warning: Failed prop type: Invalid prop children of type array supplied > > to Provider, expected a single ReactElement.
I know that Provider have to be on "top" of the app, but it's exactly what I did. I'm lost :(
Thanks for your helps guys.
You need to remove the whitespace around <App />. This:
ReactDOM.render(
<Provider store={store}> <App /> </Provider>,
document.getElementById('app')
);
should be:
ReactDOM.render(
<Provider store={store}><App /></Provider>,
document.getElementById('app')
);
the spaces in there are being treated as text nodes, i.e. additional children.

Categories

Resources