I'm working with a menu and this have a ListGroupItem and try to redirect another component with history push but only change in the url! This url works but it doesn't change the view, I have to press enter to make this work.
I'm new with react, especially with the router, and I'm feeling lost with this. Thanks for any help.
This is my App.js
import React, { Component } from 'react';
import './css/App.css';
import { BrowserRouter, Route, Link } from 'react-router-dom';
import Prueba from './Prueba';
import Menu from './header/Menu';
class App extends Component {
toggle(menu) {
if (this.state.collapse == menu){
this.setState({ collapse: false });
}else {
this.setState({ collapse: menu });
}
}
render() {
return (
<BrowserRouter>
<Menu/>
<Prueba/>
</BrowserRouter>
);
}
}
export default App;
This is my another component with name Prueba.js
import React, { Component } from 'react';
import './css/App.css';
import { BrowserRouter, Route,Link} from 'react-router-dom';
import { ListGroup, ListGroupItem,Collapse, Container, CardBody, Card, Row, Col} from 'reactstrap';
import Pais from './UbicacionGeneral/Pais';
import { withRouter } from 'react-router';
class Prueba extends React.Component{
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = { collapse: false };
this.routeChange = this.routeChange.bind(this);
}
routeChange() {
this.props.history.push('Pais');
}
componentDidUpdate(){
}
toggle(menu) {
if (this.state.collapse == menu){
this.setState({ collapse: false });
}else {
this.setState({ collapse: menu });
}
}
render() {
return (
<BrowserRouter>
<div className="App text-center">
<Row>
<Col md="2">
<ListGroup className="List-Principal">
<ListGroupItem className="List-Principal-Item " onClick={() => this.toggle("ubicacion")} > Ubicacion General </ListGroupItem>
<Collapse isOpen={this.state.collapse == "ubicacion"}>
<ListGroup>
<ListGroupItem onClick={this.routeChange} > Pais </ListGroupItem>
<ListGroupItem > Estado </ListGroupItem>
<ListGroupItem > Ciudad </ListGroupItem>
</ListGroup>
</Collapse>
<ListGroupItem className="List-Principal-Item tex-center"
onClick={() => this.toggle("almacen")} > Almacen </ListGroupItem>
<Collapse isOpen={this.state.collapse == "almacen"}>
<ListGroup>
<ListGroupItem > Crear - Modificar </ListGroupItem>
<ListGroupItem > Verificar Stock </ListGroupItem>
<ListGroupItem > Movimientos </ListGroupItem>
</ListGroup>
</Collapse>
</ListGroup>
</Col>
<Col md="10">
<Container>
<Route path="/Pais" component={Pais} />
</Container>
</Col>
</Row>
</div>
</BrowserRouter>
);
}
}
export default withRouter(Prueba);
Finally this is the component I want to see with the history push, named Pais.
Pais.js
import React, { Component } from 'react';
import { ListGroup, ListGroupItem,Collapse, Container, CardBody, Card, Row, Col} from 'reactstrap';
import { Alert } from 'reactstrap';
import { withRouter } from 'react-router-dom';
class Pais extends Component {
render() {
return (
<div>
<Alert color="primary">
This is a primary alert — check it out!
</Alert>
<Alert color="secondary">
This is a secondary alert — check it out!
</Alert>
<Alert color="success">
This is a success alert — check it out!
</Alert>
<Alert color="danger">
This is a danger alert — check it out!
</Alert>
<Alert color="warning">
This is a warning alert — check it out!
</Alert>
<Alert color="info">
This is a info alert — check it out!
</Alert>
<Alert color="light">
This is a light alert — check it out!
</Alert>
<Alert color="dark">
This is a dark alert — check it out!
</Alert>
</div>
);
}
}
export default withRouter (Pais);
There are several parts that are incorrect.
First of all, you shouldn't use BrowserRouter in Prueba.js. There should be only one BrowserRouter.
Also, you either put Route inside BrowserRouter or Switch.
As you didn't configure routes properly using BrowserRouter, Switch and Route, url changes but that doesn't reflect to your React App.
I am working on a web application using React and bootstrap. When it comes to applying button onClick, I'm having a hard time to have page being redirect to another. If after a href, I cannot go the another page.
So would you please tell me is there any need for using react-navigation or other to navigate the page using Button onClick ?
import React, { Component } from 'react';
import { Button, Card, CardBody, CardGroup, Col, Container, Input, InputGroup, InputGroupAddon, InputGroupText, Row, NavLink } from 'reactstrap';
class LoginLayout extends Component {
render() {
return (
<div className="app flex-row align-items-center">
<Container>
...
<Row>
<Col xs="6">
<Button color="primary" className="px-4">
Login
</Button>
</Col>
<Col xs="6" className="text-right">
<Button color="link" className="px-0">Forgot password?</Button>
</Col>
</Row>
...
</Container>
</div>
);
}
}
update:
React Router v6:
import React from 'react';
import { useNavigate } from "react-router-dom";
function LoginLayout() {
let navigate = useNavigate();
const routeChange = () =>{
let path = `newPath`;
navigate(path);
}
return (
<div className="app flex-row align-items-center">
<Container>
...
<Button color="primary" className="px-4"
onClick={routeChange}
>
Login
</Button>
...
</Container>
</div>
);
}}
React Router v5 with hooks:
import React from 'react';
import { useHistory } from "react-router-dom";
function LoginLayout() {
const history = useHistory();
const routeChange = () =>{
let path = `newPath`;
history.push(path);
}
return (
<div className="app flex-row align-items-center">
<Container>
...
<Row>
<Col xs="6">
<Button color="primary" className="px-4"
onClick={routeChange}
>
Login
</Button>
</Col>
<Col xs="6" className="text-right">
<Button color="link" className="px-0">Forgot password?</Button>
</Col>
</Row>
...
</Container>
</div>
);
}
export default LoginLayout;
with React Router v5:
import { useHistory } from 'react-router-dom';
import { Button, Card, CardBody, CardGroup, Col, Container, Input, InputGroup, InputGroupAddon, InputGroupText, Row, NavLink } from 'reactstrap';
class LoginLayout extends Component {
routeChange=()=> {
let path = `newPath`;
let history = useHistory();
history.push(path);
}
render() {
return (
<div className="app flex-row align-items-center">
<Container>
...
<Row>
<Col xs="6">
<Button color="primary" className="px-4"
onClick={this.routeChange}
>
Login
</Button>
</Col>
<Col xs="6" className="text-right">
<Button color="link" className="px-0">Forgot password?</Button>
</Col>
</Row>
...
</Container>
</div>
);
}
}
export default LoginLayout;
with React Router v4:
import { withRouter } from 'react-router-dom';
import { Button, Card, CardBody, CardGroup, Col, Container, Input, InputGroup, InputGroupAddon, InputGroupText, Row, NavLink } from 'reactstrap';
class LoginLayout extends Component {
constuctor() {
this.routeChange = this.routeChange.bind(this);
}
routeChange() {
let path = `newPath`;
this.props.history.push(path);
}
render() {
return (
<div className="app flex-row align-items-center">
<Container>
...
<Row>
<Col xs="6">
<Button color="primary" className="px-4"
onClick={this.routeChange}
>
Login
</Button>
</Col>
<Col xs="6" className="text-right">
<Button color="link" className="px-0">Forgot password?</Button>
</Col>
</Row>
...
</Container>
</div>
);
}
}
export default withRouter(LoginLayout);
Don't use a button as a link. Instead, use a link styled as a button.
<Link to="/signup" className="btn btn-primary">Sign up</Link>
React Router v5.1.2:
import { useHistory } from 'react-router-dom';
const App = () => {
const history = useHistory()
<i className="icon list arrow left"
onClick={() => {
history.goBack()
}}></i>
}
This can be done very simply, you don't need to use a different function or library for it.
onClick={event => window.location.href='/your-href'}
I was trying to find a way with Redirect but failed. Redirecting onClick is simpler than we think. Just place the following basic JavaScript within your onClick function, no monkey business:
window.location.href="pagelink"
First, import it:
import { useHistory } from 'react-router-dom';
Then, in function or class:
const history = useHistory();
Finally, you put it in the onClick function:
<Button onClick={()=> history.push("/mypage")}>Click me!</Button>
A very simple way to do this is by the following:
onClick={this.fun.bind(this)}
and for the function:
fun() {
this.props.history.push("/Home");
}
finlay you need to import withRouter:
import { withRouter } from 'react-router-dom';
and export it as:
export default withRouter (comp_name);
useHistory() from react-router-dom can fix your problem
import React from 'react';
import { useHistory } from "react-router-dom";
function NavigationDemo() {
const history = useHistory();
const navigateTo = () => history.push('/componentURL');//eg.history.push('/login');
return (
<div>
<button onClick={navigateTo} type="button" />
</div>
);
}
export default NavigationDemo;
If all above methods fails use something like this:
import React, { Component } from 'react';
import { Redirect } from "react-router";
export default class Reedirect extends Component {
state = {
redirect: false
}
redirectHandler = () => {
this.setState({ redirect: true })
this.renderRedirect();
}
renderRedirect = () => {
if (this.state.redirect) {
return <Redirect to='/' />
}
}
render() {
return (
<>
<button onClick={this.redirectHandler}>click me</button>
{this.renderRedirect()}
</>
)
}
}
if you want to redirect to a route on a Click event.
Just do this
In Functional Component
props.history.push('/link')
In Class Component
this.props.history.push('/link')
Example:
<button onClick={()=>{props.history.push('/link')}} >Press</button>
Tested on:
react-router-dom: 5.2.0,
react: 16.12.0
If you already created a class to define the properties of your Button (If you have a button class created already), and you want to call it in another class and link it to another page through a button you created in this new class, just import your "Button" (or the name of your button class) and use the code below:
import React , {useState} from 'react';
import {Button} from '../Button';
function Iworkforbutton() {
const [button] = useState(true);
return (
<div className='button-class'>
{button && <Button onClick={()=> window.location.href='/yourPath'}
I am Button </Button>
</div>
)
}
export default Iworkforbutton
A simple click handler on the button, and setting window.location.hash will do the trick, assuming that your destination is also within the app.
You can listen to the hashchange event on window, parse the URL you get, call this.setState(), and you have your own simple router, no library needed.
class LoginLayout extends Component {
constuctor() {
this.handlePageChange = this.handlePageChange.bind(this);
this.handleRouteChange = this.handleRouteChange.bind(this);
this.state = { page_number: 0 }
}
handlePageChange() {
window.location.hash = "#/my/target/url";
}
handleRouteChange(event) {
const destination = event.newURL;
// check the URL string, or whatever other condition, to determine
// how to set internal state.
if (some_condition) {
this.setState({ page_number: 1 });
}
}
componentDidMount() {
window.addEventListener('hashchange', this.handleRouteChange, false);
}
render() {
// #TODO: check this.state.page_number and render the correct page.
return (
<div className="app flex-row align-items-center">
<Container>
...
<Row>
<Col xs="6">
<Button
color="primary"
className="px-4"
onClick={this.handlePageChange}
>
Login
</Button>
</Col>
<Col xs="6" className="text-right">
<Button color="link" className="px-0">Forgot password </Button>
</Col>
</Row>
...
</Container>
</div>
);
}
}
With React Router v5.1:
import {useHistory} from 'react-router-dom';
import React, {Component} from 'react';
import {Button} from 'reactstrap';
.....
.....
export class yourComponent extends Component {
.....
componentDidMount() {
let history = useHistory;
.......
}
render() {
return(
.....
.....
<Button className="fooBarClass" onClick={() => history.back()}>Back</Button>
)
}
}
I was also having the trouble to route to a different view using navlink.
My implementation was as follows and works perfectly;
<NavLink tag='li'>
<div
onClick={() =>
this.props.history.push('/admin/my- settings')
}
>
<DropdownItem className='nav-item'>
Settings
</DropdownItem>
</div>
</NavLink>
Wrap it with a div, assign the onClick handler to the div. Use the history object to push a new view.
Make sure to import {Link} from "react-router-dom";
And just hyperlink instead of using a function.
import {Link} from "react-router-dom";
<Button>
<Link to="/yourRoute">Route Name</Link>
</Button>
I researched this answer in couple of stackoverflow threads but nothing worked so far. I am using Reactstrap Collapse toggle, but instead of an outside button, I have the onClick method on an "li" tag.
The problem is that I am trying to stopPropagation to the additional "li's" without success. so if I click on one li, every li open, and closes.
import React, { Component } from 'react';
import { Col, Collapse, ListGroup, ListGroupItem } from 'reactstrap';
import Data from '../data/data.json';
class Example extends Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
collapse: false,
Data: Data
};
}
toggle = (e) => {
this.setState({ collapse: !this.state.collapse });
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
}
render() {
return (
<Col xs={12} md={6} lg={6} className="right-col">
<ListGroup onClick={this.toggle}>
{ Data.projectLinks.map((link) => {
return <ListGroupItem key={link.title} onClick={(e) => {this.toggle(e)}}>
{link.title}
<Collapse isOpen={this.state.collapse}>
<p>{link.description}</p>
</Collapse>
</ListGroupItem>
})
}
</ListGroup>
</Col>
);
}
}
export default Example;
If you have any idea how to accomplish this, or another solution here, I appreciate it.
I have 5 such list items i.e self , parents , siblings , relative, friend. Clicking on any item , I am adding a class called active-option . Below is my code , what I have done so far. To note , I am a new to React JS.
import React, { Component } from 'react';
import {Grid, Col, Row, Button} from 'react-bootstrap';
import facebook_login_img from '../../assets/common/facebook-social-login.png';
const profilesCreatedBy = ['Self' , 'Parents' , 'Siblings' , 'Relative' , 'Friend'];
class Register extends Component {
constructor(props) {
super(props);
this.state = { addClass: false };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ addClass: !this.state.addClass });
}
render() {
let selectOption = ["option"];
if (this.state.addClass) {
selectOption.push("active-option");
}
return (
<section className="get-data__block" style={{padding: '80px 0 24px 0'}}>
<Grid>
<Row>
<Col sm={10} md={8} mdOffset={2} smOffset={1}>
<p className="grey-text small-text m-b-32"><i>
STEP 1 OF 6 </i>
</p>
<div className="data__block">
<div className="step-1">
<p className="m-b-32">This profile is being created by</p>
<Row>
{profilesCreatedBy.map((profileCreatedBy, index) => {
return <Col className="col-md-15">
<div onClick={this.handleClick} className={selectOption.join(" ")}>
{profileCreatedBy}
</div>
</Col>;
})}
</Row>
</div>
<Row className="text-center">
<Col xs={12} className="text-center">
<Button href="#" bsStyle="primary" className="m-t-96 m-b-16 has-box__shadow" >
Continue
</Button>
</Col>
</Row>
</div>
</Col>
</Row>
</Grid>
</section>
);
}
}
export default Register;
I am using a map function to display all items. I have tried to add a class called active-option to option. But clicking on any item is adding the class to every other item also. (Attached) Any suggestion ? I want to add active-option class to the one where click event happens, not to every other element. Siblings should not contain active-option class. Please help !
You can achieve this with keeping active item id in the state of component, for example:
class Test extends React.Component{
constructor(){
super();
this.state = {
activeId: null
}
this.setActiveElement = this.setActiveElement.bind(this);
}
setActiveElement(id){
this.setState({activeId: id})
}
render(){
return(
<div>
{
[1,2,3,4,5].map((el, index) =>
<div className={index === this.state.activeId? "active" : ""} onClick={() => this.setActiveElement(index)}>click me</div>
)
}
</div>
)
}
}
https://jsfiddle.net/69z2wepo/85095/
I have been working on my first Meteor application and am a bit stuck. I want to create my code following the latest guidelines (ES6 and React 15) but I am confused with all the recent changes in Javascript.
I want to add a Bootstrap Modal in my current comments list but can't seem to figure out how to add my content to the modal using the right up to date syntax.
Here is my current code:
In comment.js:
import React from 'react';
import { Row, Col, ListGroupItem, FormControl, Button } from 'react-bootstrap';
import { Bert } from 'meteor/themeteorchef:bert';
import { CommentsModal } from './comments-modal'
export const Comment = ({ comment }) => (
<ListGroupItem key={ comment._id }>
<Row>
<Col xs={ 8 } sm={ 10 }>
<FormControl
type="text"
defaultValue={ comment.title }
/>
</Col>
<Col xs={ 4 } sm={ 2 }>
<Button
bsStyle="danger"
className="btn-block">
Remove Comment
</Button>
</Col>
</Row>
<CommentsModal/>
</ListGroupItem>
);
In Comments-modal.js:
import React, { Component } from 'react';
import { Modal, Button, Tooltip } from 'react-bootstrap';
export class CommentsModal extends Component {
constructor(props) {
super(props);
this.state = {
showModal: false,
};
this.close = this.close.bind(this);
this.open = this.open.bind(this);
}
close() {
this.setState({ showModal: false });
}
open() {
this.setState({ showModal: true });
}
render() {
return (
<div>
<Button
bsStyle="primary"
bsSize="large"
onClick={this.open}
>
</Button>
<Modal show={this.state.showModal} onHide={this.close}>
<Modal.Header closeButton>
<Modal.Title >Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>
<h4>Text in a modal</h4>
</Modal.Body>
<Modal.Footer>
<Button onClick={this.close}>Close</Button>
</Modal.Footer>
</Modal>
</div>
);
}
}
And last comments-list.js:
import React from 'react';
import { ListGroup, Alert } from 'react-bootstrap';
import { Comment } from './comment';
export const CommentsList = ({ comments }) => (
comments.length > 0 ? <ListGroup className="comments-list">
{comments.map((com) => (
<Comment key={ com._id } comment={ com } />
))}
</ListGroup> :
<Alert bsStyle="warning">No comments yet. Please add some!</Alert>
);
CommentsList.propTypes = {
comments: React.PropTypes.array,
};
I manage to get the Modal to show up and work but when I want to display data in it, I can't get it to work. What is the best way to combine both these into one?
Pass the data in props to the CommentsModal and render it as you would normally do.
I try to keep local state out of component when using redux if possible, so to answer your question on making it stateless, I would take the following steps:
Remove the button that opens the modal from the modal.js itself
Remove the actual modal from the modal.js, just put the modal content inside of there.
Change the open modal button to hook into an action creator that sets a prop to open the modal and passes it's content (also set one to close it)
So that looks something like this
<ListGroupItem key={ comment._id }>
<Row>
<Col xs={ 8 } sm={ 10 }>
<FormControl
type="text"
defaultValue={ comment.title }
/>
</Col>
<Col xs={ 4 } sm={ 2 }>
<Button
bsStyle="danger"
className="btn-block">
Remove Comment
</Button>
</Col>
</Row>
<!-- Here is where it changes, -->
<Button
bsStyle="primary"
bsSize="large"
onClick={this.props.openModal(comment)}
>
</Button>
<Modal show={this.props.commentModal} onHide={this.props.closeModal}>
<CommentsModal content={this.props.commentModal} />
</Modal>
Keep in mind, these naming conventions are just for examples sake : use whatever works best for you.
So what happens here is when you click that button you fire this.props.openModal (an action) which does something like this in the reducers -
case actions.OPEN_COMMENT_MODAL:
return state.set('commentModal', action.content);
the close buttons fire the onHide which is linked to the this.props.closeModal action which just does:
case actions.OPEN_COMMENT_MODAL:
return state.set('commentModal', undefined);
So what this allows you to do is have just 1 modal instance and you pass the current comment to it with that button click and open it. The show just checks the truthy value, so you set it back to undefined and it will hide itself.
Then I am passing the prop of content to the modal, so you can then use it inside the modal itself. Again, change the names to whatever works best for you.