Is there a way to click Navlink from within a function? - reactjs

Basically, I'm delaying the navigation.
After clicking the Link, the onClick handler prevents the navigation by checking a condition and calls another function. If certain condition is met, then only the page navigates to another.
So how can I trigger Navlink click from within that function.

I was able to solve this problem by using event.preventDefault().
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'
import Modal from './Modal'
var confirmation = {};
class Example extends Component {
handleClick(event) {
if(this.props.data.length!=0) {
confirmation = {
prompt: (
<div className="row">
<div className="col s12 m5"><a className="btn" onClick={this.props.actions.toggleModal()}>No</a></div>
<div className="col s12 m7"><NavLink to={"/"+this.props.endpoint+"/1"} activeClassName="active" className="btn"}>Yes, Navigate to Option 1</NavLink></div>
</div>
)
}
event.preventDefault();
}
}
render() {
return (
<div>
<nav>
<div className="row">
<div className="col s10">
<ul className="col s12">
<li className="col s4 m4 l3"><NavLink to={"/"+this.props.endpoint+"/1"} activeClassName="active" onClick={this.handleClick.bind(this)}>Option 1</NavLink></li>
<li className="col s4 m4 l3"><NavLink to={"/"+this.props.endpoint+"/2"} activeClassName="active">Option 2</NavLink></li>
<li className="col s4 m4 l3"><NavLink to={"/"+this.props.endpoint+"/3"} activeClassName="active">Option 3</NavLink></li>
</ul>
</div>
</div>
</nav>
{
this.props.openModal ?
<Modal data={confirmation}/>
: null
}
</div>
)
}
}
export default example

Instead of using the react-router Link component, you can use their API to programmatically navigate to another page (if the certain condition is met).
export default class MyComponent extends Component {
navCheck(nextPage) {
if (someCondition) {
this.context.router.history.push(nextPage);
}
}
render() {
return(<a onClick={() => this.navCheck('/next-page')}>Navigate To Another Page</a>);
}
}
MyComponent.contextTypes = {
router: PropTypes.shape({
history: PropTypes.object.isRequired,
}),
};
More information on the official documentation: https://reacttraining.com/react-router/web/api/history

Related

How to fix: How to show state with onClick to div?(React)

I have sidebar with document types on it(docs, table, slider, html ..). I want that, if i click on docs element it will show docs in another div like a header.
I have 3 files: DocumentType.tsx, Sidebar.tsx and Results.tsx
In DocumentType.tsx:
import React from 'react';
const documentType = (props ) =>{
return(
<div>
<p id="fileType">{props.type}</p>
</div>
)
};
export default documentType;
In Sidebar.tsx:
typeState = {
documentTypes: [
{ type: "Dokumendid" },
{ type: "PDF" },
]
}
toDocument = () => {
this.setState({
documentTypes: [
{ type: "Dokumendid" }
console.log("Document was clicked");
]
})
}
toPdf = () => {
this.setState({
documentTypes: [
{ type: "Pdf" }
console.log("PDF was clicked")
]
})
}
render(){
return(
<a className="a" href="/search?filter%3Atype=doc" onClick={this.toDocument}>
<div className="icons dokument">
<img src={dokument} alt="dokument"/>
<a className="title">dokument</a>
</div>
</a>
<a className="a" href="/search?filter%3Atype=pdf" onClick={this.toPdf}>
<div className="icons pdf">
<img src={pdf} alt="pdf"/>
<a className="title">pdf</a>
</div>
</a>
)
}
And in Results.tsx:
...
<DocumentType />
..
You want to show a document type in Results component when a document in Sidebar component is clicked.
You have documentType state in Sidebar component and you want to pass it to Results component. So for that you can make Results component as child component of Sidebar component and pass the selected document type i.e documentType state as props.
Sidebar.js
import React, {Component} from 'react'
import Results from 'path-to-results';
class Sidebar extends Component {
state = {
// instead of using "documentType" as array
// you can make it null for initial value
documentType: null
}
// instead of using "toPDF" or "toDocument" method
// you can use single method to update the state
handleDocType = (docType) => {
this.setState({
documentType: docType
})
}
render() {
return (
<div>
// pass "document" as argument to handleDocType method
<a className="a" href="#" onClick={() => this.handleDocType('document')}>
<div className="icons dokument" >
<img src="" alt="dokument"/>
<a className="title">dokument</a>
</div>
</a>
// pass "pdf" as argument to handleDocType method
<a className="a" href="#" onClick={() => this.handleDocType('pdf')}>
<div className="icons pdf">
<img src="" alt="pdf"/>
<a className="title">pdf</a>
</div>
</a>
// checking if "documentType" is null or not
// if it is null nothing is rendered
// if it is not null then "Results" component is rendered
{ this.state.documentType && <Results type={this.state.documentType} /> }
</div>
)
}
}
Results.js
import React, { Component } from 'react'
import DocType from 'path-to-doctype'
class Results extends Component {
// .... your other codes
render() {
return (
<div>
// ....... your other codes
<DocType type={this.props.type} />
</div>
)
}
}
export default Results
DocType.js
import React from 'react';
const DocumentType = (props ) =>{
return(
<div>
<p id="fileType">{props.type}</p>
</div>
)
};
export default DocumentType;
UPDATE
If Sidebar and DocType components are children components of Results component then add documentType state to Results component and pass documentType state as props to DocType component.
Results.js
class Results extends Component {
// add state "documentType"
state = {
documentType: null
}
// add "handleDocType" method
handleDocType = (docType) => {
this.setState({
documentType: docType
})
}
// .... your other codes
render() {
return (
<div>
// .... your other codes
// pass "handleDocType" as props to Sidebar component
<Sidebar handleDocType={this.handleDocType}/>
// pass "documentType" state as props to DocType component
<DocType type={this.state.documentType} />
</div>
)
}
}
export default Results
Sidebar.js
class Sidebar extends Component {
// use "docTypeHandler" to call parent "handleDocType" method
// that updates "documentType" state in Results component
docTypeHandler = (doctype) => {
this.props.handleDocType(doctype)
}
render() {
return (
<div>
<a className="a" href="#" onClick={() => this.docTypeHandler('document')}>
<div className="icons dokument" >
<img src="" alt="dokument"/>
<a className="title">dokument</a>
</div>
</a>
<a className="a" href="#" onClick={() => this.docTypeHandler('pdf')}>
<div className="icons pdf">
<img src="" alt="pdf"/>
<a className="title">pdf</a>
</div>
</a>
</div>
)
}
}
export default Sidebar
DocType.js
const DocType = (props ) =>{
return(
<div>
<p id="fileType">{props.type}</p>
</div>
)
};
If I understood your question correctly.. you wanted to show data in a div when onClick event triggers..
lets say your state object has
state = {
data: ''
}
//clicked function
clicked =() => {
this.setState({data: 'clickedme'})
}
div element: <div onClick={this.clicked} >{this.state.data}</div>
simple example when an onClick event occurs a div and displaying the state data object..

How to call twofunction in componentDidMount?

I failed to call two funtion in componentDidMount.When I clicked bangla its change and when i clicke english its change but during routing it stays only english so i wanted to set the state in componentDidMount,but it only invoke one funtion.if click the bangla it set bangla but when i change the routing its remain the same lang. so how can i set it.
import React, { Component } from 'react';
import { connect } from "react-redux";
import {setLanguage} from "../../actions";
import { Link } from "react-router-dom";
class MenuComp extends Component {
constructor(props){
super(props);
this.setLang = this.setLang.bind(this);
this.state= {
"maintitle": {
"titlelist": [
{"title1":"Timetable"},
{"title2":"Ticket Prices"},
{"title3":"About Us"}
]
}
};
}
setLang(lang){
this.props.setLanguage(lang);
this.props.history.push('/menu');
}
changeLanguage = () => {
this.setState({
"maintitle": {
"titlelist": [
{"title1":"সময়সূচী"},
{"title2":"টিকেটর মূল্য"},
{"title3":"আমাদের সম্পর্কে"}
]
}
});
};
changeLang = () => {
this.setState({
"maintitle": {
"titlelist": [
{"title1":"Timetable"},
{"title2":"Ticket Prices"},
{"title3":"About Us"}
]
}
});
};
componentDidMount() {
this.changeLanguage();
this.changeLang();
}
render() {
return (
<div className="Menu">
<div className="menu-header">
<div className="container-fluid p-0">
<div className="row m-0">
<div className="col-md-4 p-0 d-flex justify-content-end">
<div className="align-self-center">
<a className="lang" onClick={() => { this.setLang('bn'); this.changeLanguage(); }}>Bangla</a> |
<a className="lang l-active" onClick={() => { this.setLang('en'); this.changeLang(); }}>English</a>
</div>
</div>
</div>
</div>
</div>
<main className="navigation">
<div className="container-fluid p-0">
<div className="row m-0">
<div className="col-md-4 pl-0">
<Link to="/timetable" className="lang">
<div className="card-content">
<h6 className="card-title">{
this.state.maintitle.titlelist.map((title, i)=>{
return (<p key={i}>{title.title1} </p>)
})
}</h6>
</div>
</Link>
</div>
<div className="col-md-4 pl-0">
<Link to="/ticketprice" className="lang">
<div className="card-content">
<h6 className="card-title">{
this.state.maintitle.titlelist.map((title, i)=>{
return (<p key={i}>{title.title2} </p>)
})
}</h6>
</div>
</Link>
</div>
</Link>
</div>
</div>
</div>
</main>
</div>
);
}
}
function mapStateToProps(state){
return {
lang: state.lang.lang
}
}
const Menu = connect(mapStateToProps, {setLanguage})(withRouter(MenuComp));
export default Menu;
It's an asynchronous problem. So, the setState method runs asynchronously. This makes reading this.state right after calling setState() a potential pitfall.
So, the lines inside your componentDidMount method get executed, however, you can't predict which one of them will finish before the other.
Now, I don't completely understand what you're trying to achieve, but instead, use componentDidUpdate or a setState callback (setState(updater, callback)): something like this:
this.setState((state, props)=> ({
"maintitle": {
"titlelist": [
{"title1":"সময়সূচী"},
{"title2":"টিকেটর মূল্য"},
{"title3":"আমাদের সম্পর্কে"}
]
}
}), ()=> {// do what you want next!})
// (this could be inside your componentDidMount!
If that didn't help, please let me know!

ReactJS Hamburger icon not toggling

I am using this library for front end which is based on Bulma and I'm facing issues with Hamburger Icon Here is the documentation Example, but again this is something not very easy to understand. I have searched for a workaround and a solution for this, but I cannot find it, I'm doing it in ES6 Style, and here is my code.
import React, { Component } from "react";
import { Navbar } from "react-bulma-components/full";
class MenuNavbar extends Component {
render() {
return (
<div id="header">
<Navbar color="info" fixed="top">
<Navbar.Brand>
<Navbar.Item renderAs="a" href="/">
<img src="https://i.imgur.com/9jQaBuq.png" alt="Dew Ventures" />
</Navbar.Item>
<Navbar.Burger />
</Navbar.Brand>
<Navbar.Menu>
<Navbar.Container>
<Navbar.Item href="/">Home</Navbar.Item>
<Navbar.Item href="/about"> About Us</Navbar.Item>
<Navbar.Item href="/contact"> Contact Us</Navbar.Item>
</Navbar.Container>
</Navbar.Menu>
</Navbar>
</div>
);
}
}
export default MenuNavbar;
<Navbar.Burger
active={open}
onClick={() =>
this.setState(state => {
open: !state.open;
})
}
/>
From the Storybook you linked to, the example shows that there is an onClick handler that sets the state to change the hamburger into a cross. You need to have some kind of handler that sets the active prop to true. That will change the hamburger to a cross whenever you click the component.
And from the source code of that library for the burger component within the Navbar that you're using, the component requires you to pass in the active prop as true to set the is-active css class, which Bulma uses natively to change the hamburger to a cross:
import React, { Component } from "react";
import { Navbar } from "react-bulma-components/full";
class MenuNavbar extends Component {
// set active state for hamburger
state = { active : false }
handleClick = () => {
const { active } = this.state;
this.setState({ active: !active });
}
render() {
return (
<div id="header">
<Navbar color="info" fixed="top" active={this.state.active}>
<Navbar.Brand>
<Navbar.Item renderAs="a" href="/">
<img src="https://i.imgur.com/9jQaBuq.png" alt="Dew Ventures" />
</Navbar.Item>
<Navbar.Burger
active={this.state.active}
onClick={this.handleClick}
/>
</Navbar.Brand>
<Navbar.Menu>
<Navbar.Container>
<Navbar.Item href="/">Home</Navbar.Item>
<Navbar.Item href="/about"> About Us</Navbar.Item>
<Navbar.Item href="/contact"> Contact Us</Navbar.Item>
</Navbar.Container>
</Navbar.Menu>
</Navbar>
</div>
);
}
}
export default MenuNavbar;
You can toggle navbar in pure Bulma CSS with ref usage:
burger = React.createRef();
menu = React.createRef();
toggle = () => {
if (this.menu.current.classList.contains("is-active")) {
this.menu.current.classList.remove("is-active");
} else {
this.menu.current.classList.add("is-active");
}
};
this approach adopted also for your case
Plug and Play React usag utilizing UseEffect...
Remember to add the nav-toggle and navbar-menu classes to your burger and nav respectively
useEffect(() => {
(function() {
var burger = document.querySelector('.nav-toggle');
var menu = document.querySelector('.navbar-menu');
burger.addEventListener('click', function() {
burger.classList.toggle('is-active');
menu.classList.toggle('is-active');
});
})();
}, [])
<nav className="navbar">
<div className="navbar-brand is-1">
<a href="/" className="navbar-item">
<img src={logo} alt="YMCA"/>
</a>
<button className="navbar-burger burger is-white button nav-toggle"
aria-label="menu" aria-expanded="false" data-target="Options">
<span></span>
<span></span>
<span></span>
<span></span>
</button>
</div>
<div className="navbar-menu is-8 is-offset-a" id="Options">
<div className="navbar-end mt-2">
<button type="submit">Association Level Prediction</button>
<button type="submit" >Custom Prediction</button>
<button type="submit" onClick={() => handleNavigate(ROUTE_ABOUT)} className={checkIfActive(ROUTE_ABOUT)}>About</button>
<button type="submit" onClick={() => handleLogout()} className={checkIfActive('logout')}>Logout</button>
</div>
</div>
</nav>

React Sort By Like

I am trying to figure out how to add an onClick feature that will then sort the likes in descending order. AKA each project has a 'like' button. I want to add another button to the page to allow the user to sort the project likes by descending order.
import React from 'react';
import ProjectsListItem from './ProjectsListItem'
const Project = ({ projects }) => {
const renderProjects = projects.projects.map(project =>
<ProjectsListItem project={project} key={project.id}/>
);
return (
<div className="container">
<div className="row">
{renderProjects}
</div>
</div>
);
};
export default Project;
Page 2
class ProjectsListItem extends Component {
handleOnClick = () => {
this.props.likeProject(this.props.project)
}
onClick = () => {
this.props.sortBy(this.props.project.like)
}
render() {
return(
<div>
<div className="col-sm-4">
<div className="container-fluid text-left">
<h4> <Link key={this.props.project.id} to=
{`/projects/${this.props.project.id}`}>{this.props.project.title}
</Link> </h4>
<h5> {this.props.project.studio}</h5>
<CounterButton project={this.props.project} likeProject=
{this.handleOnClick}/>
</div>
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
projects: state.projects
}
}
export default connect(mapStateToProps, {likeProject})
(ProjectsListItem);
You would have to make an event handler such as
https://reactjs.org/docs/handling-events.html
In this case you would probably want to do
onSortClick(e) {
e.preventDefault();
this.props.sorted = true
}
bind that to your click handler like this:
<CounterButton project={this.props.project} likeProject=
{this.onSortClick.bind(this)}/>
Hope this helps.

ReactJS OnClick render

I am new to ReactJS and I am trying to make a menu that by pressing any of the functions the active class will disappear and the new page will appear. In here for instance, I am trying to click on My Order and get forwarded to the page I asked to load. How do I make this correctly? Here is my current code:
import React from 'react';
import ReactDOM from 'react-dom';
import "./index.css";
class MainPanel extends React.Component {
render() {
return (
<div className="main-layout">
<header>
<ul className="top">
<h1>Header</h1>
</ul>
</header>
<ul className="categories">
<li>Main Panel</li>
<li onClick={<MyOrder />}>My Order</li>
<li>Technical Support</li>
<li>My Payments</li>
<li>Suggestions/ Questions</li>
</ul>
</div>
);
}
}
function MyOrder () {
return (
<div className="main-layout">
<header>
<ul className="top">
<h1>My Order</h1>
</ul>
</header>
<ul className="categories">
<li>Where is my order?</li>
<li>My order delays more than the expected time</li>
<li>My order status shows that the order arrived but it did not</li>
<li>I have a complaint</li>
<li>Suggestions/ Questions</li>
</ul>
</div>
);
}
ReactDOM.render(
<MainPanel />,
document.getElementById('root')
);
Without React Router and other 3rd party libraries you could do something like this:
class Overview extends React.Component {
onMenuClick(id) {
return this.props.onMenuClick(id);
}
render() {
return(
<ul className="categories">
<li onClick={this.onMenuClick.bind(this, "mainPanel")}>Main Panel</li>
<li onClick={this.onMenuClick.bind(this, "myOrder")}>My Order</li>
<li onClick={this.onMenuClick.bind(this, "technicalSupport")}>Technical Support</li>
<li onClick={this.onMenuClick.bind(this, "myPayments")}>My Payments</li>
<li onClick={this.onMenuClick.bind(this, "suggestions")}>Suggestions/ Questions</li>
</ul>
);
}
}
class MainPanel extends React.Component {
// sets the initial value for this.state.page
componentWillMount() {
this.setState({
page: "overview"
});
}
switchPage(id) {
this.setState({ page: id });
}
showComponent() {
if(this.state.page === "overview") return (<Overview
onMenuClick={::this.switchPage}
/>);
if(this.state.page === "myOrder") return <MyOrder />;
throw new Error(`${this.state.page} is not a valid page id`);
}
render() {
return (
<div className="main-layout">
<header>
<ul className="top">
<h1>Header</h1>
</ul>
</header>
{ this.showComponent() }
</div>
);
}
}
You change the view by updating the state. Depending on the state different components are mounted/unmounted.
Note based on my experience: Try to handle your app state (in our case the current page information) via React Baobab or something like this (centralized state) because otherwise all these props bubblings become confusing.

Resources