Render React Component based on React-Route - reactjs

I am trying to render a specific component inside of another component based on React, React-Router v4, and Redux in my main 'panel' wrapped in a fixed header and sidebar component.
For example when I select an item from the sidebar, I to render the Detail panel and and load the details based on the id, like: <Route path='/item/:id' component={ItemDetail} />
routes.js
import React, { Component } from 'react';
import { RouteHandler, Switch, Route, DefaultRoute } from 'react-router';
import App from './containers/App';
import Login from './containers/Login';
import LobbyDetail from './components/LobbyDetail';
export default (
<Switch>
<Route exact path="/" component={App} />
<Route exact path="/login" component={Login} />
</Switch>
);
app.js:
import React, { Component } from 'react'
import { Router, Route, Link } from 'react-router'
import { connect } from 'react-redux'
import PropTypes from 'prop-types';
import auth from '../actions/auth';
import Sidebar from '../Components/Sidebar'
class App extends Component {
static propTypes = {
};
/**
*
*/
render() {
const { ... } = this.props
return (
<div className="container-fluid">
<div className="row">
{* I WANT TO RENDER DYNAMIC COMPONENT HERE *}
</div>
<Sidebar currentUser={currentUser}
logout={logout}
/>
</div>
);
}
}
// ...
export default connect(mapStateToProps, mapDispatchToProps)(App)
index.js (basically main app):
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import { createMemoryHistory } from 'history';
import routes from './routes';
import configureStore from './store/store.js';
import { AppContainer } from 'react-hot-loader';
const syncHistoryWithStore = (store, history) => {
const { routing } = store.getState();
if (routing && routing.location) {
history.replace(routing.location);
}
};
const initialState = {};
const routerHistory = createMemoryHistory();
const store = configureStore(initialState, routerHistory);
syncHistoryWithStore(store, routerHistory);
const rootElement = document.querySelector(document.currentScript.getAttribute('data-container'));
const render = () => {
ReactDOM.render(
<AppContainer>
<Provider store={store}>
<ConnectedRouter history={routerHistory}>
{routes}
</ConnectedRouter>
</Provider>
</AppContainer>,
rootElement
);
}
render();
if (module.hot) { module.hot.accept(render); }

What you're looking for is parameterized routing. Make a <Route/> like the following: <Route path='/item/:id' component={ MyComponent } />.
Now in MyComponent you can use the value of props.match.params.id to conditionally render, or if you're trying to load async data based on the value of :id; You can use the componentWillReceiveProps life cycle method and dispatch an action based on the value of this.props.match.params.id.
Note: <Link to='/item/some-item'/> will set the value of match.params.id to 'some-item'.

Related

How to get ReactRouter Props , while using Redux

App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
// import browserRoute
import { BrowserRouter, Switch, Route, Link } from 'react-router-dom'
// redux
import Todo from './todo/Todo';
import Login from './todo/Login';
import Home from './todo/Home';
import Callender from './Callender/Callender'
import WhetherData from './Callender/CallenderComponent'
import { localstoreExport } from './index';
export default class App extends Component {
render() {
return (
<BrowserRouter>
< Switch>
<Route path="/todo">
<Todo />
</Route>
<Route path="/login">
<Login />
</Route>
<Route path ="/callender">
<Callender />
</Route>
<Route path="/climateshow" component ={WhetherData}/>
<Route exact path="/" component={Home}/>
</Switch>
</BrowserRouter>
</Provider>
)
}
}
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
// Redux
import { createStore,combineReducers,applyMiddleware,compose } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
// import reducer
import todoReducer from './store/reducers/rootReducer';
import whetherReducer from './store/reducers/callender'
// combine the Reducer
const rootReducer = combineReducers({
todoReducer,
whetherReducer
})
// chrome extension helper
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
// create a store
const store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk)));
export const localstoreExport = store;
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
Callender.js
import React, { Component } from 'react';
import { DatePicker, DatePickerInput } from 'rc-datepicker';
import 'rc-datepicker/lib/style.css';
import axios from 'axios'
import { connect } from 'react-redux';
// redux components
import { getDataFromApi } from '../store/actions/callender'
class Callender extends Component {
state = {
totalDate:''
}
// These is the complete code for getting the response from version 2 of api
onChange = (event) =>{
console.log(event);
this.setState({
totalDate:event
})
this.props.getWhetherData()
{console.log(this.props.whetherData)}
}
render() {
const date = '2015-06-26';
return (
<div>
<DatePicker onChange={this.onChange} value={date} />
{this.props.whetherData? console.log(this.props.history): null}
</div>
)
}
}
const mapStateToProps = state =>{
return {
whetherData: state.whetherReducer.whetherData
}
}
const mapDispatchToProps = dispatch =>{
return {
getWhetherData : () => dispatch(getDataFromApi())
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Callender);
1)In the following code I have written my Routes, in App.js file and created store in Index.js
2) In Callender.js i want to push my route to whether data end Point so i am trying to see the this.props.history it is showing undefined
3) so i tried to see my props by this.props Now it is showing me the redux props so i realized that
my router props are getting overridden by redux props
4) how to use history push while using redux
You can wrap your component with withRouter.
import { withRouter } from "react-router";
export default connect(mapStateToProps,mapDispatchToProps)(withRouter(Callender));
You can find detailed example here.

Meteor/React Router: error message "there is no route defined"

Unfortunately, I can't get React Router to work in my custom meteor boilerplate and I really can't figure out why. Here's all the files that could potentially be relevant to the problem:
\client\main.js:
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import { renderRoutes } from '../imports/startup/client/routes.jsx';
Meteor.startup(() => {
render(renderRoutes(), document.getElementById('app'));
});
\imports\startup\client\routes.jsx:
import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
// route components
import App from '../../ui/App.jsx';
export const renderRoutes = () => (
<Router>
<div>
<Route path="/" component={App} />
</div>
</Router>
);
\imports\ui\App.jsx
import React from 'react';
import { withTracker } from 'meteor/react-meteor-data';
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<h1>Hey!</h1>
);
}
}
export default withTracker(() => {
return {
};
})(App);
Any idea why the error message might occur? Thanks!
Not sure what version of meteor and react you are using but tha's how i did it on the last project i had.
Try this changes:
import {Router, Route, browserHistory} from 'react-router';
export const renderRoutes = () => (
<Router history={browserHistory}>
<div>
<Route path="/" component={App} />
</div>
</Router>
);

react-router-dom route component requires page reload

When calling history.push('/packages') the url is updated but the component will not mount (render) unless the page is reloaded. If I call createHistory({forceRefresh: true}) or manually reload the page the UI is rendered correctly. How can I configure react-router-dom to load the component without explicitly reloading the page or using forceRefresh?
index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import store from './store'
import {Provider} from 'react-redux'
import App from './App'
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('app')
);
App.jsx
import React, { Component } from 'react'
import { Switch, Route } from 'react-router-dom'
import PropTypes from 'prop-types'
import { Navbar, PageHeader, Grid, Row, Col } from 'react-bootstrap'
import LoginFormContainer from './components/Login/LoginFormContainer'
import PackageContainer from './components/Package/PackageContainer'
class App extends Component {
render() {
return (
<Grid>
<Navbar>
<Navbar.Header>
<Navbar.Brand><h3>Mythos</h3></Navbar.Brand>
</Navbar.Header>
</Navbar>
<Row className="content">
<Col xs={12} md={12}>
<Switch>
<Route path='/packages' render={() => <PackageContainer />} />
<Route exact path='/' render={() => <LoginFormContainer />} />
</Switch>
</Col>
</Row>
</Grid>
)
}
}
export default App
loginActions.jsx
import * as types from './actionTypes'
import LoginApi from '../api/loginApi'
import createHistory from 'history/createBrowserHistory'
const history = createHistory()
export function loginUser(user) {
return function(dispatch) {
return LoginApi.login(user).then(creds => {
dispatch(loginUserSuccess(creds));
}).catch(error => {
throw(error);
});
}
}
export function loginUserSuccess(creds) {
sessionStorage.setItem('credentials', JSON.stringify(creds.data))
history.push('/packages')
return {
type: types.LOGIN_USER_SUCCESS,
state: creds.data
}
}
PackageContainer.jsx
import React, { Component } from 'react'
import {connect} from 'react-redux'
import PropTypes from 'prop-types'
import {loadPackages} from '../../actions/packageActions'
import PackageList from './PackageList'
import ImmutablePropTypes from 'react-immutable-proptypes'
import {Map,fromJS,List} from 'immutable'
import {withRouter} from 'react-router-dom'
class PackageContainer extends Component {
constructor(props, context) {
super(props, context);
}
componentDidMount() {
this.props.dispatch(loadPackages());
}
render() {
return (
<div className="col-lg-12">
{this.props.results ?
<PackageList results={this.props.results} /> :
<h3>No Packages Available</h3>}
</div>
);
}
}
PackageContainer.propTypes = {
results: ImmutablePropTypes.list.isRequired,
};
const mapStateToProps = (state, ownProps) => {
return {
results: !state.getIn(['packages','packages','results']) ? List() : state.getIn(['packages','packages','results'])
};
}
PackageContainer = withRouter(connect(mapStateToProps)(PackageContainer))
export default PackageContainer
I assume, that issue that you are create new instance of history object but BrowserRouter doesn't know about the changes which happens inside of it.
So, you should create history object and export it in the index.jsx and use Router instead of BrowserRouter and pass as history property, so then you can just import it whenever you need.
For example:
index.jsx
import { Router } from 'react-router-dom'
import createHistory from 'history/createBrowserHistory'
...
export const history = createHistory()
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<App />
</Router>
</Provider>,
document.getElementById('app')
);
Then, in loginActions you just import history and use .push method as before.
loginActions.jsx
import * as types from './actionTypes'
import LoginApi from '../api/loginApi'
import { history } from './index'
export function loginUser(user) {
return function(dispatch) {
return LoginApi.login(user).then(creds => {
dispatch(loginUserSuccess(creds));
}).catch(error => {
throw(error);
});
}
}
export function loginUserSuccess(creds) {
sessionStorage.setItem('credentials', JSON.stringify(creds.data))
history.push('/packages')
return {
type: types.LOGIN_USER_SUCCESS,
state: creds.data
}
}
Hope it will helps.
In the App.jsx
<Switch>
<Route path='/packages' render={(props) => <PackageContainer {...props}/>} />
<Route exact path='/' render={(props) => <LoginFormContainer {...props}/>} />
</Switch>
Now both PackageContainer and LoginFormContainer have access to history object

Values is redux store reverting to original state after switching view

I'm having an issue in where by I switch routes, and the value of a property in my store is reverting back to it's original state. I'm using react 16 with react router v4.
I'm also noticing that the entire App component rerenders when I change routes. That seems over the top. It's running mapStateToProps and mapDispatchToProps every time. I'm noticing the state passed into mapStateToProps is always empty too.
I'm very puzzled.
main file
import React from 'react';
import { render } from 'react-dom';
import { connect } from 'react-redux';
//install routing deps
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './store'
import App from './components/App';
render(
<Provider store={store}>
<BrowserRouter>
<App/>
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
store
import { createStore, compose, applyMiddleware} from 'redux';
import rootReducer from './reducers/index';
const defaultState = { count: 0 };
const enhancers = compose(
window.devToolsExtension ? window.devToolsExtension() : f => f,
);
const store = createStore(rootReducer, defaultState, enhancers);
//adds hot reload for changes to reducer
if(module.hot){
module.hot.accept('./reducers', ()=>{
const nextRootReducer = require(`./reducers/index`).default;
store.replaceReducer(nextRootReducer);
});
};
export default store;
App component
import React, { Component } from 'react';
import { Route, Switch, Redirect, Link } from 'react-router-dom';
import { BrowserRouter, withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as actionCreators from '../actions/actionCreators';
class App extends Component {
constructor() {
super();
};
render() {
return (
<div>
main
<a href='/info'>info</a>
<Switch>
<Route exact path="/" render={() => <h1>kawaii world</h1>} />
<Route exact path="/info" render={() => <h1>v kawaii world ;)</h1>} />
</Switch>
</div>
);
};
};
function mapStateToProps(state) {
return {
count: state.count
};
};
function mapDispatchToProps(dispatch) {
return bindActionCreators(actionCreators, dispatch);
};
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App));
If you make use of tag a literally you are saying that you are willing to go to another page but in react apps that's not the case. In react you navigate from one component to another.
So to fix your issue you need to do this:
import { BrowserRouter, Link, withRouter } from 'react-router-dom';
class App extends Component {
render() {
return (
<div>
<Link to="/">Main</Link>
<Link to="/info">Info</Link>
<Switch>
<Route exact path="/" render={() => <h1>kawaii world</h1>} />
<Route exact path="/info" render={() => <h1>v kawaii world ;)</h1>} />
</Switch>
</div>
);
};
};

React Router won't render any other routes

I'm on the latest version of React, React-router, React-router-redux, and react-redux but I can't seem to get any other routes other than my App to render. All I get is a blank page. I'm not doing any nesting, but I suspect it might have to do with my setup... also no errors crop up when examining in console.
my index.js looks like this:
import 'babel-polyfill';
// Write entry-point js for webpack here....
import React from 'react';
import {render} from 'react-dom';
import {Provider} from 'react-redux';
import App from './containers/App';
import configureStore from './store/configureStore'
import { Router, Route, browserHistory } from 'react-router';
import { PasswordResetView } from './views/PasswordResetView';
import {Test} from './components/Test';
const store = configureStore()
const reactEntry = document.getElementById('react-root');
// Render....
render(
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={App}/>
<Route path="/test" component={Test}/>
</Router>
</Provider>,
reactEntry
)
my App.js is this:
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { loginUser } from '../../actions';
import Navbar from '../../components/Navbar';
import {Link} from 'react-router';
class App extends Component {
render() {
const { dispatch, isAuthenticated, errorMessage, isFetching } = this.props
return(
<div>
<div>
<Navbar
isFetching={isFetching}
isAuthenticated={isAuthenticated}
errorMessage={errorMessage}
dispatch={dispatch}/>
</div>
{this.props.children}
<div>
<Link to="/test">Test</Link>
</div>
</div>
)
}
}
App.propTypes = {
dispatch: PropTypes.func.isRequired,
isFetching: PropTypes.bool.isRequired,
isAuthenticated: PropTypes.bool.isRequired,
errorMessage: PropTypes.string
}
const mapStateToProps = (state) => {
const { isAuthenticated, errorMessage, isFetching } = state.auth
console.log(state.auth)
return {
isAuthenticated,
errorMessage,
isFetching
}
}
export default connect(mapStateToProps)(App)
My Test.js file
import React, {Component} from 'react'
export default class Test extends Component {
render(){
return (
<div>Test</div>
)
}
}
Any help whatsoever would be much appreciated!! I'm sure I've screwed something up somewhere...
I ended up rewriting my App component as more of a home/parent component to house my other routes. I'm guessing I was misusing react-router and had some sort of problem rendering between child and parent routes (although I did use this.props.children to test that.. who knows!)
render(
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={App}/>
<Route path="/register(/:token)" component={RegistrationCompleteView}/>
<Route path="/resend-confirmation" component={ResendConfirmationView}/>
<Route path="/password-reset" component={PasswordRequestView}/>
<Route path="/password-reset(/:token)" component={PasswordCompleteView}/>
<Route path="/login" component={LoginView}/>
</Router>
</Provider>,
reactEntry

Resources