React-Router 1.0.0beta3 sub link not working properly - reactjs

While there are no errors being reported, the Example page is not appearing after clicking on "Go to Example Page".
But, if I do not make the Example route a sub-route to Main, the Example Page works but I no longer have the Main Page as a Header.
Can anyone see where my error is?
Using:
"react": "^0.14.0-beta2",
"react-dom": "^0.14.0-beta2",
"react-router": "^1.0.0-beta3"
// Bootstrapping module
import React, {Component} from 'react';
import ReactDom from 'react-dom';
import { history } from 'react-router/lib/BrowserHistory';
import Routes from 'routes';
let rootEl = document.getElementById('content');
ReactDom.render(<Routes history={history} />, rootEl);
//Routes.js
import React, { PropTypes, Component } from 'react';
import { Router, Route, Link } from 'react-router';
import Main from 'components/main';
import Example from 'components/example.js';
export default class Routes extends Component {
static propTypes = {
history: PropTypes.object.isRequired
}
render() {
const { history } = this.props;
return (
<Router history={history}>
<Route path="/" component={Main}>
<Route path="/example" component={Example}>
</Route>
</Route>
</Router>
);
}
}
//Example.js
import React from 'react';
import connectToStores from 'alt/utils/connectToStores';
import DummyStore from 'stores/dummyStore';
import DummyActions from 'actions/dummyActions';
#connectToStores
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
name: props.name
}
}
static getStores(props) {
return [DummyStore];
}
static getPropsFromStores(props) {
return DummyStore.getState();
}
render() {
return (
<div>
<input type="text" value={this.state.name} onChange={this.onChange}/>
<h1>On example Page: {this.props.name}</h1>
</div>
);
}
onChange = evt => {
this.setState({name: evt.target.value});
DummyActions.updateName(evt.target.value);
}
}
export default Example;

I found the solution, but I want to add first I am very concerned about the documentation for react-router, not to mention react in general. It seems as if the react framework and related enhancements as so fluid, one can not grasp any cohesive understanding of the framework for the long term.
Here is the solution, it requires a change in the Main Component to include children props:
class Main extends React.Component {
render() {
return (
<div>
<h1>Main Top Header</h1>
<Link to='example'>Go to the Example page...</Link>
{this.props.children} <--- solution
</div>
);
}
}
Note:
As of today, and that is about as good as it gets because this framework is way too fluid for my liking, when you have nested routes, the parent route must include {this.props.children} in the component class.
But, it appears, that in the world of react, this could all be invalid tomorrow!!

Related

TypeError: instance.render is not a function while using react-router-dom

Hi If any one can help. Thanks in advance
In console I am also getting this
index.js:1 Warning: AppBootUp(...): No render method found on the returned component instance: you may have forgotten to define render
this is my App.js
import React from "react";
import AppRoutes from "../routes/routers";
import { createStore } from 'redux'
import rootReducer from '../store/reducers/index'
import {Provider} from "react-redux";
const store = createStore(rootReducer);
export default class AppBootUp extends React.Component<> {
static render() {
return (
<Provider store={store}>
<AppRoutes/>
</Provider>
);
}
}
this is my AppRoutes
import React from "react";
import { BrowserRouter as Router, Redirect, Route, Switch } from "react-router-dom";
import Login from "../components/Login/login"
const routesConfig = [
{
path: "/",
component: Login,
name: "Login",
exact: true
}
];
const AppRoutes = () => {
return (
<Router>
<Switch>
{routesConfig.map(config => {
return (
<Route
exact={config.exact && true}
key={`${config.name}`}
path={config.path}
render={(props) => {
const ComponentToRender = config.component;
return <ComponentToRender {...props} />;
}}
/>
);
})}
<Redirect to="/" />
</Switch>
</Router>
);
};
export default AppRoutes;;
this is login.js
import React from "react";
export default class Login extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<p>
hello
</p>
</div>
);
}
}
I am using react-router-dom. I think, I am missing something little here.
Remove static method from render method in AppBootUp class. If you define a render method as static, it won't be available in class instance, which is why you are getting this error.
export default class AppBootUp extends React.Component<> {
render() {
return (
<Provider store={store}>
<AppRoutes/>
</Provider>
);
}
}
You need to remove static before render method of AppBootUp.
render shouldn't be a static property of React class component otherwise it won't exist on component's instance and would become unavailable.
As static properties don't exist on class instance but on the Class itself.
Remove static before render in Appboot.
render should not be a static property of React class component otherwise it won't exist on component's instance.
As static properties don't exist on class instance but on the Class itself.
Normally this happens when you accidentally alt+enter on render in Webstorm.
when it shows warning that this method can be static.

React-router custom prop not passing to component. ternary operator not working correctly

In React i have my App.js page where i keep my states. I'm importing user1.js component to App.js, and in user1.js component i have a link button that takes me to path /user2.
When i click the button, React will set state property called testValue to true and in user2.js page ternary operator should choose the first value - test works because of that. But for some reason it does not work.
Any help?
APP.JS
import React, { Component } from 'react';
import './App.css';
import User1 from './components/user1';
class App extends Component {
constructor(props){
super(props);
this.state = {
testValue:false
};
}
change = () => {
this.setState({
testValue:true
},() => {
console.log(this.state.testValue)
});
}
render() {
return (
<div className="App">
<User1 change={this.change}/>
</div>
);
}
}
export default App;
USER1.JS
import React from 'react';
import { BrowserRouter, Route, Switch, Link } from 'react-router-dom';
import User2 from './user2.js';
const User1 = (props) => {
return(
<BrowserRouter>
<div>
<Link to ="/user2">
<button onClick={props.change}>Next page</button>
</Link>
<Switch>
<Route path="/user2" exact component={User2}/>
</Switch>
</div>
</BrowserRouter>
); // end of return
};
export default User1;
USER2.JS
import React from 'react';
const User2 = (props) => {
console.log(props)
return(
<div>
{props.testValue ?
<p>test works</p>
:
<p>test does not work</p>
}
</div>
);
};
export default User2;
This is what i expected - test works
This is what i got - test does not work
You want to pass a custom property through to a component rendered via a route. Recommended way to do that is to use the render method.
<Route path="/user2" exact render={(props) => <User2 {...props} testValue={true} />} />
I think a valid inquiry here would be what are you wanting to pass through as an extra prop? whats the use case here? You may be trying to pass data in a way you shouldn't (context would be nice :D).

Cannot read property 'push' of undefined in react

import React, {PropTypes} from 'react';
export default class Login extends React.Component {
constructor(props) {
super(props)
this.handleLogin = this.handleLogin.bind(this)
}
handleLogin(event) {
event.preventDefault()
// do some login logic here, and if successful:
this.props.history.push(`/Home`)
}
render() {
return (
<div>
<form onSubmit={this.handleLogin}>
<input type='submit' value='Login' />
</form>
</div>
)
}
}
I am getting Cannot read property 'push' of undefined in the console. Now how to access the push in the react-router v4.
thanks in advance!
By default use can't use browserHistory in react router 4 as you can use in react router 3, still you can use different ways to push by withRouter or context but i will recommend
use withRouter HOC.
You should use the withRouter high order component, and wrap that to the component that will push to history. For example:
import React from "react";
import { withRouter } from "react-router-dom";
class MyComponent extends React.Component {
...
myFunction() {
this.props.history.push("/HOME");
}
...
}
export default withRouter(MyComponent);
If you're using react router you need to wrap your component withRouter to have the history prop injected into your component.
import {withRouter} from 'react-router-dom';
...
export default withRouter(MyComponent);
Also whatever components you use this must be children of your router component at the top level.
Looks like your component is not wrapped with router. wrap it with withRouter.
import React, { PropTypes } from "react";
import { withRouter } from "react-router-dom";
class Login extends React.Component {
constructor(props) {
super(props);
this.handleLogin = this.handleLogin.bind(this);
}
handleLogin(event) {
event.preventDefault();
// do some login logic here, and if successful:
this.props.history.push(`/Home`);
}
render() {
return (
<div>
<form onSubmit={this.handleLogin}>
<input type="submit" value="Login" />
</form>
</div>
);
}
}
export default withRouter(Login);
You have to use useNavigate if you installed v6 or more than "react-router-dom": ^6.2.1
import { useNavigate } from "react-router-dom";
let navigate = useNavigate();
const onSubmit = async (e) => {
e.preventDefault();
await axios.post("http://localhost:3001/users", user);
navigate(`/`);
};
Please read this link if you want know more about it and this video has a very useful practice to understand it. The video page is 'React Router V6 Tutorial - Routes, Redirecting, UseNavigate, UseParams...' in 'PedroTech' page on YouTube.
Wrap your component withRouter to have the history prop so you can use push
Here are the requirements that should make it work:
required imports for index.js:
import { Provider } from 'react-redux';
import { createHashHistory } from 'history';
import { ConnectedRouter, connectRouter, routerMiddleware } from 'connected-react-router';
in your main App.js you need:
const history = createHashHistory();
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</Provider>,
rootEl,
);
There where you want to use push:
import { push as RouterPush } from 'react-router-redux';

Props don't seem to be passed along in a React app

I recently started working with React so forgive me if my question is very basic. Props in a component don't seem to be passed along.
Below is my code.
dogDetails component
import React from 'react';
const DogDetails = (props) => {
return (
<div>
<h4>{'Dog details of '+ props.breed}</h4>
</div>
)
};
export default DogDetails;
In Dog component I have a method that returns a DogDetails component as shown below.
import React , {Component} from 'react'
import Dog from './Dog/Dog';
import classes from './Dogs.css';
import Aux from '../../hoc/Auxillary/Auxillary';
import {Route} from 'react-router-dom';
import DogDetails from './Dog/DogDetails/DogDetails';
class Dogs extends Component {
state = {
loadedDogs: []
};
componentDidMount () {
this.setState({
loadedDogs:[]
})
}
dogDetailsHandler = (dog) =>{
console.log(dog.breed);
return <DogDetails breed={dog.breed}/>;
};
render() {
const loadDogs = this.state.loadedDogs.map(dog => {
return <Dog
url={dog.images[0].image1}
alt={dog.id}
breed={dog.breed}
temperament={dog.temperament}
id={dog.id}
key={dog.id}
clicked ={() => this.dogDetailsHandler(dog)}>
</Dog>
});
return (
<Aux>
{loadDogs}
</Aux>
)
}
}
export default Dogs;
I have omitted the content of the loadedDogs array to reduce the code size.
Below is the Dog component
import React from 'react';
import classes from './Dog.css';
import {Link, Route} from 'react-router-dom';
const dog = (props) => {
return(
<div className={classes.Dog}>
<div>
<img src={props.url} alt ={props.id}/>
</div>
<div>
<h4>{'Breed: ' + props.breed}</h4>
<h5>{'Temperament: ' + props.temperament}</h5>
<p>
<Link to = '#'>... Read more ...</Link>
</p>
<Link to={'/shop/'+ props.id}>
<button onClick={props.clicked}>Order</button>
</Link>
</div>
</div>
)
};
export default dog;
I'm routing the DogDetails in the MainContent component like this.
import React from 'react';
import classes from './MainContent.css';
import Dogs from './Dogs/Dogs';
import Contact from '../Contact/Contact';
import {Route} from 'react-router-dom';
import DogDetails from './Dogs/Dog/DogDetails/DogDetails';
const main = () =>{
return (
<div className={classes.MainContent}>
<Route path='/' exact component = {Dogs}/>
<Route path='/shop' exact component = {Dogs}/>
<Route path={'/shop/:id'} exact component={DogDetails}/>
<Route path='/contact' exact component ={Contact}/>
</div>
)
};
export default main;
Here is a sample code sandbox to demonstrate what I'm trying to work on. I want the DogDetails component to show up when the Order button is clicked.
Code Sandbox
The dogDetails component <h4> tag is returning undefined. Please help me find where I'm doing it wrong.
Capitalize both dogDetails and dogDetailsHandler
User-Defined Components Must Be Capitalized
from react docs
Codesandbox example
Since you are using routing, I'm not sure why you have a button handler inside of a routed <Link />. Clicking on this element will route you to /shop/:id, and the return method of dogDetailsHandler will do nothing.
I have emulated your code and added a <Route /> I'm not sure if this is what you are after, but when I click "Order", I'll get routed to /shop/:id with the DogDetails component being rendered as it should.
Add this routing component after your <Link /> component and see if this is the behavior you are after.
<Route path="/shop/:id" render={
() => <DogDetails {...props} />
} />

React router v4 not working with Redux

Developing a React application using React router v4. All worked well until I introduced Redux in my app. Since then on click of links to change route the browser url changes but the component corresponding to the route is not getting loaded. It works well if I comment out Redux code. What could be causing this? Here is my code for routing:
import React, { Component } from 'react';
import { Switch, Route, Link } from 'react-router-dom';
import LeftSubDefault from './../components/left-sub-default.component';
import LeftSubOne from './../components/left-sub-one.component';
import LeftSubTwo from './../components/left-sub-two.component';
import { withRouter } from 'react-router-dom';
import { connect } from "react-redux";
import { goToLeftDefault, goToLeftOne, goToLeftTwo } from "./../actions/leftRouteActions.js";
class LeftComponent extends Component {
render() {
return (
<div className="col-xs-6">
<p>
Current sub route: {this.props.currentRoute}
</p>
<ul>
<li onClick={this.props.goToDefault}><Link to={'/'}>Go To Default</Link></li>
<li onClick={this.props.goToSub1}><Link to={'/left-sub1'}>Go To One</Link></li>
<li onClick={this.props.goToSub2}><Link to={'/left-sub2'}>Go To Two</Link></li>
</ul>
<Switch>
<Route exact path='/' component={LeftSubDefault} />
<Route exact path='/left-sub1' component={LeftSubOne} />
<Route exact path='/left-sub2' component={LeftSubTwo} />
</Switch>
</div>
);
}
}
const mapStateToProps = (store) => {
return {
currentRoute: store.routes.currentRoute
};
}
const mapDispatchToProps = (dispatch) => {
return {
goToDefault: () => {
dispatch(goToLeftDefault())
},
goToSub1: () => {
dispatch(goToLeftOne())
},
goToSub2: () => {
dispatch(goToLeftTwo())
}
};
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(LeftComponent));
PS: I get no error in console. The code runs clean just components don't load. Here is a similar thread on github: 4671. I have seen lot of threads on various sites but none has the solution for this issue.
Hah, now I'm making a project with react-router and redux too =).
Look at the official documentation about redux integration https://reacttraining.com/react-router/web/guides/redux-integration.
I think the main point is order of withRouter and connect Hocs.
The problem is that Redux implements shouldComponentUpdate and there’s no indication that anything has changed if it isn’t receiving props from the router. This is straightforward to fix. Find where you connect your component and wrap it in withRouter.
From the official docs.
UPD
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
class Home extends React.Component {...}
export default withRouter(
connect(mapStateToPropsFunc)(Home)
);
I'm using react-router-dom v4.1.1. It is working for me. Here is my Demo
import React from 'react';
import Reducer1 from 'yourReducer1';
import Reducer2 from 'yourReducer2';
import {
Route,
Switch as RouterSwitch
} from 'react-router-dom';
const App =()=> (
<RouterSwitch>
<Route path="/link1" exact component={Reducer1}/>
<Route path="/link2" exact component={Reducer2}/>
</RouterSwitch>
);
export default App;
Hope it is helpful for you ^^

Resources