Calling function in App.js from another component - reactjs

I'm new to ReactJS and want to use this library: https://github.com/teodosii/react-notifications-component
It states that "You must place ReactNotificationsComponent component at the root level of the application in order to work properly, otherwise it might conflict with other DOM elements due to the positioning."
I followed the usage guide, but I'm not sure how to call the addNotification function from a child component.
App.js
import React, { Component } from 'react'
import ReactNotification from "react-notifications-component"
import Header from './components/Header'
class App extends Component {
constructor() {
super()
this.addNotification = this.addNotification.bind(this)
this.notificationDOMRef = React.createRef()
}
addNotification() {
this.notificationDOMRef.current.addNotification({
title: "Awesomeness",
message: "Awesome Notifications!",
type: "success",
insert: "top",
container: "top-right",
animationIn: ["animated", "fadeIn"],
animationOut: ["animated", "fadeOut"],
dismiss: { duration: 5000 },
dismissable: { click: true }
})
}
render() {
return (
<div>
<ReactNotification ref={this.notificationDOMRef} />
<Header />
</div>
)
}
}
export default App
Header.js
import React, { Component } from 'react'
import logo from "../assets/images/logo/logo-light.png"
import { BrowserRouter as Router, Route, NavLink, Switch } from "react-router-dom"
import Home from '../pages/Home'
import Apply from '../pages/Apply'
export default class Header extends Component {
render() {
return (
<Router>
<div>
<Route render={({ location }) => (
<header id="navbar-spy" className="header header-1 header-dark header-fixed">
<nav id="primary-menu" className="navbar navbar-fixed-top">
<div className="container">
<div className="navbar-header">
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse-1" aria-expanded="false">
<span className="sr-only">Toggle navigation</span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
</button>
<img className="logo-light" src={logo} alt="Logo" draggable="false" />
</div>
<div className="collapse navbar-collapse pull-right" id="navbar-collapse-1">
<ul className="nav navbar-nav nav-pos-right navbar-left">
<li className="">
<NavLink to="/" className="menu-item">Home</NavLink>
</li>
<li className="">
<NavLink to="/apply" className="menu-item">Apply</NavLink>
</li>
</ul>
</div>
</div>
</nav>
</header>
)}
/>
<Route path="/" exact component={Home} />
<Route path="/apply" exact component={Apply} />
</div>
</Router>
)
}
}
When you click the "Apply" link, it loads the Apply component. In that component, they can receive an error/success notification. From that component is where I want to be able to tell the ReactNotification in App.js what title, message, and type to render. How can I communicate from Apply.js to App.js?

You can pass the addNotification function to your Header component:
<Header addNotification={this.addNotification} />
And you can continue to pass it down to other child components, until you are ready to call it.

Related

passing component & props in function react js

i have 2 components & i want to pass data by input from parent component to the child component, i got stuck to pass the data to the child component and display or render the child component
is there any technique to pass the props to the child components & render it?
and when i see the console on developer tools there is nothing wrong/happen except the console.log code
import React, {Component} from 'react';
import ReactDOM from'react-dom';
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
//props.keyword
const keyword = 'avenger';
const API = `https://api.themoviedb.org/3/search/movie?api_key=341c549444f65b6a022eea5fc24f5b77&language=en-US&query=${keyword}&page=1&include_adult=false`;
const DEFAULT_QUERY = 'redux';
class MovieSearch extends Component{
constructor(props){
super(props);
this.state={
movies:[]
}
}
componentDidMount(){
fetch(API + DEFAULT_QUERY)
.then(response=>response.json())
.then(data=>{
this.setState({movies:data.results})
})
}
render(){
const {movies} = this.state;
return(
<div className="row container">
{movies.map(movie =>
<div className="col-md-4">
<div className="card" style={{width: '15rem'}} key={movie.id}>
<img src="" className="card-img-top" alt="..."/>
<div className="card-body">
<h5 className="card-title">{movie.title}</h5>
<p>{movie.id}</p>
<Link to="/movie/detail">Detail</Link>
</div>
</div>
</div>
)}
</div>
)
}
}
export default MovieSearch;
import React, { Component } from"react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
//component
import Jumbotron from "./jumbotron";
import MovieList from "./movieList";
import MovieSearch from"./MovieSearch";
import Movie from"./Movie";
//HOC
const idMovie = (WrappedComponent)=>{
class IdMovie extends Component{
constructor(props){
super(props)
this.state={}
}
}
}
//route start here
class Main extends Component{
constructor(props){
super(props)
this.state={
keyword: ''
}
this.handleInput = this.handleInput.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleInput(event){
this.setState({keyword:event.target.value})
}
handleSubmit(event){
console.log(this.state.keyword)
event.preventDefault()
}
render(){
return (
<Router>
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
<Link className="navbar-brand" to="/">Carifilm</Link>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarSupportedContent">
<ul className="navbar-nav mr-auto">
<li className="nav-item active">
<Link className="nav-link" to="/">Home <span className="sr-only">(current)</span></Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/movies">Movies</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/search-movie">Cari film</Link>
</li>
</ul>
<form className="form-inline my-2 my-lg-0" onSubmit={this.handleSubmit}>
<input className="form-control mr-sm-2"
type="search" placeholder="Search"
aria-label="Search"
value={this.state.keyword}
onChange={this.handleInput}/>
<button className="btn btn-outline-success my-2 my-sm-0" type="submit" value="submit">Search</button>
</form>
</div>
</nav>
<Switch>
<Route exact path="/">
<Home/>
</Route>
<Route path="/movies">
<Movies/>
</Route>
<Route path="/movie/detail">
<MovieDetail/>
</Route>
<Route path="/search-movie">
<CariFilm/>
</Route>
</Switch>
</Router>
)}
}
export default Main;
function Home(){
return(
<Jumbotron/>
)
}
function Movies(){
return(
<MovieList/>
)
}
function MovieDetail(){
return(
<Movie/>
)
}
function CariFilm(props){
return(
<MovieSearch/>
)
}
Please check this example. Here I passed items into my Child Component and displayed items in child component.
Parent
import React, {Component, useEffect, useState} from 'react';
import {PChild} from "./PChild";
export class Parent extends Component {
constructor(props) {
super(props);
this.state = {items: []};
}
componentDidMount() {
let json = [];
json.push({track: { id:1, name: 'Black Sabbath, from the album Black Sabbath (1970)'}});
json.push({track: { id:2, name: 'Blackfield, from the album Blackfield (2004)'}});
json.push({track: { id:3, name: 'Bo Diddley, from the album Bo Diddley (1958)'}});
json.push({track: { id:4, name: 'Damn Yankees, from the album Damn Yankees (1990)'}});
this.setState({items: json});
}
render() {
return (
<div>
<PChild items={this.state.items} name="Khabir"/>
</div>
);
}
}
Child
import React, {useEffect, useState} from 'react';
// Parent to Child communication
export class PChild extends React.Component {
componentDidUpdate() {
console.log(this.props.items);
console.log(this.props.name);
}
render() {
return (
<div>
{this.props.items.map((item, i) => {
return <li key={item.track.id}>
{(`Item ${i+1} - ${item.track.name}`)}
</li>
})}
</div>
);
}
}

React Page Refresh the Whole Page after Clicking on a link

I've just started using reactJS and i am integrating an HTML admin template in react which has header, sidebar, footer and the main section content.
One thing i'm a bit curious is whenever i click links in the main section content, only the specific section dynamically loads, but when i click on links in sidebar the entire page reloads, why is it so? Below is the code that i'm following
App.js
import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import Header from './Components/Header';
import Content from './Components/Content';
import Footer from './Components/Footer';
import Sidebar from './Components/Sidebar';
const App = () => {
return(
<BrowserRouter>
<Header/>
<Sidebar/>
<Content/>
<Footer/>
</BrowserRouter>
);
}
export default App;
Header.jsx
import React from 'react';
import logo from '../stack.png';
const Header = () => {
return(
<nav>
</nav>
);
}
export default Header;
Sidebar.jsx
import React from 'react';
import { Link } from 'react-router-dom';
const Sidebar = () => {
return(
<aside>
<div className="main-menu menu-fixed menu-dark menu-accordion menu-shadow" data-scroll-to-active="true">
<div className="main-menu-content">
<ul className="navigation navigation-main" id="main-menu-navigation" data-menu="menu-navigation">
<li style={{'margin': '25px 0 0 0'}} className="active nav-item">
<Link to="/dashboard">
<i className="ft-home"></i>
<span className="menu-title">
Dashboard
</span>
</Link>
</li>
<li className="nav-item"></i><span className="menu-title" data-i18n="">Create</span>
<ul className="menu-content">
<li className=" menu-item">
<Link to="/create">
<span className="menu-title">
Create New
</span>
</Link>
</li>
<li className=" menu-item">
<Link to="/createxyz">
<span className="menu-title">
Create XYZ
</span>
</Link>
</li>
</ul>
</li>
</ul>
</div>
</div>
</aside>
);
}
export default Sidebar;
Content.jsx
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import Dashboard from './Dashboard';
import Enter from './Enter';
import Enterxyz from './Enterxyz';
const Content = () => {
return(
<Switch>
<Route exact path="/" component={Dashboard} />
<Route path="/dashboard" component={Dashboard} />
<Route path="/create" component={Enter} />
<Route path="/createxyz" component={Enterxyz} />
</Switch>
);
}
export default Content;
Footer.jsx
import React from 'react';
function Footer()
{
return(
<footer className="footer footer-static footer-light navbar-border">
<p className="clearfix blue-grey lighten-2 text-sm-center mb-0 px-2">
<span className="float-md-left d-block d-md-inline-block">© 2020
<a className="text-bold-800 grey darken-2" href="">
xyz
</a> (All Rights Reserved)
</span>
</p>
</footer>
);
}
export default Footer;
Code snippet in import Enter from './Enter';
import React from 'react';
import { Link } from 'react-router-dom';
const Enter = () => {
return(
<div className="app-content content">
<div className="content-wrapper">
<div className="content-body">
<div className="row">
<div className="col-md-12">
<div className="card" style={{'height': 'auto'}}>
<div className="card-header">
<h4 className="card-title" id="basic-layout-form">Create New Client</h4>
<a className="heading-elements-toggle"><i className="fa fa-ellipsis-v font-medium-3"></i></a>
<div className="heading-elements">
<ul className="list-inline mb-0">
<li><Link to="/dashboard">Dashboard</Link></li>
<li><i className="ft-chevrons-right"></i></li>
<li><a>Create</a></li>
<li><i className="ft-chevrons-right"></i></li>
<li><Link to="/create">Enter New</Link></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
export default Enter;
in the Enter code snippet there are 2 links(Breadcrumbs) when i click on them the page loads dynamically without refresh.
But when i click on the links in sidebar, the entire page reloads to display the content, why is it so? What is wrong?

How to get another component when I click h1 tag in react using hooks?

I am working on react project in that project Home.js is Parent component and Test.js is Child component. In Home.js component I have tag here what I am trying to do is If I Click tag I need to call Test.js component. For this In Home.js I created one function and, To that function I passed Test.js component. and I passed that function via onClick method to h1 tag but its not working. How to achieve this.
This is App.js
import React from 'react';
import './App.css';
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
import Navbar from './Components/Navbar/Navbar';
import Home from "./Pages/Home/Home";
import Test from "./Pages/Test/Test";
function App() {
return (
<div className="App">
<Router>
<Navbar></Navbar>
<Switch>
<Route exact path='/'><Home></Home></Route>
<Route path='/test'><Test></Test></Route>
</Switch>
</Router>
</div>
);
}
export default App;
This is Navbar.js
import React from 'react';
import './Navbar.css';
import { Link } from 'react-router-dom';
export default function Navbar() {
return (
<div className='container'>
<div className='row'>
<div className='col-12'>
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<a className="navbar-brand" href="#">Navbar</a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav">
<li className="nav-item active">
<Link className='nav-link' to='/'>Home</Link>
</li>
</ul>
</div>
</nav>
</div>
</div>
</div>
)
}
This is Home.js
import React from 'react';
import './Home.css';
import { Link } from 'react-router-dom';
import Test from '../Test/Test';
export default function Home() {
const Test = () => {
<Test></Test>
}
return (
<div className='container'>
<div className='row'>
<div className='col-12'>
<div>
<h1 onClick={Test}>Cruse</h1>
</div>
</div>
</div>
</div>
)
}
This is Test.js
import React from 'react'
export default function Test() {
return (
<div>
<h1>Test works</h1>
</div>
)
}
I would say you are using event handlers wrong. Their purpose is to produce some kind of side effects, and they don't return a direct result. If you wish to show new element on click i recommend using react state and something like this:
export default function Home() {
const [isTestVisible, setTestVisible] = useState(false);
const showTest= () => setTestVisible(true);
return (
<div className='container'>
<div className='row'>
<div className='col-12'>
<div>
<h1 onClick={showTest}>Cruse</h1>
{isTestVisible && <Test />}
</div>
</div>
</div>
</div>
)
}
In your state you could save different props for each test component so you can customize them. Hope this helps :)
Using states is the correct answer as #Kaca992 said. But for what you do, you can do something like this:
const Test = () => {
ReactDOM.render(<Test/>, document.getElementsByTagName("h1")[0]);
}

Highlight current page in bootstrap with react

I have seen multiple questions related to this and I have tried them all, with no results. So, posting yet another seemingly duplicate question.
I am trying to highlight the current page button in the navigation bar. For simple examples, where I am not routing it to a new page, it works. But when I route it to a different page (a separate react component) it doesn't work.
Here is the code I have:
App.jsx:
class App extends Component {
render() {
return (
<BrowserRouter>
<div>
<Route exact={true} path='/' component={HomeApp}/>
<Route path='/form' component={SomeForm}/>
</div>
</BrowserRouter>
);
}
}
NavigationBar.jsx
class NavigationBar extends Component {
componentDidMount() {
toggleIcon();
}
render() {
return (<div id="topheader">
<nav className="navbar navbar-expand-lg navbar-light bg-light ">
<a className="navbar-brand" href="#">Whatever</a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav nav nav-pills ml-auto">
<li className="nav-item active">
<a className="nav-link" href="/">Home <span className="sr-only">(current)</span></a>
</li>
<li className="nav-item">
<a className="nav-link" href="/form">Submit Form</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#">Sign Up</a>
</li>
<li className="nav-item">
<a className="nav-link " href="#">Login</a>
</li>
</ul>
</div>
</nav>
</div>
)
}
}
export default NavigationBar
navigation.js
import $ from 'jquery';
export function toggleIcon() {
$( '#topheader .navbar-nav a' ).on( 'click', function () {
$( '#topheader .navbar-nav' ).find( 'li.active' ).removeClass( 'active' );
$( this ).parent( 'li' ).addClass( 'active' );
});
}
As seen, the highlighting works when I click Sign Up or Login, as they are not being routed to any other component.
But when I click on Submit Form which is routed to SomeForm component, the highlighting goes back to Home button.
For more details, I am posting the contents of HomeApp and SomeForm components:
HomeApp.jsx
class HomeApp extends Component {
render() {
return (
<div className="container">
<NavigationBar/>
<Jumbotron/>
</div>
)
}
}
export default HomeApp
SomeForm.jsx
class SomeForm extends Component {
render() {
return (<>
<div className="container">
<NavigationBar>
</NavigationBar>
</div>
</>
)
}
}
export default SomeForm
Please follow along this structure:
import { BrowserRouter, Switch, Route } from "react-router-dom"
class App extends React.Component{
render() {
return (
<BrowserRouter>
<div className="App">
<Navigation />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/about" component={About} />
<Route exact path="/contact" component={MoreRoutes} />
</Switch>
</div>
</BrowserRouter>
)
}
}
And you need to use NavLink as #Mikail Bayram mentioned, that will allow you to use activeClassName also, the exact prop is required on each of your routes to have routes render only when the path is have the exact match. Please note that you can call the active class whatever you like.
Your Navigation should look like this:
import { NavLink } from "react-router-dom"
const Navigation = () => (
<nav>
<ul>
<li>
<NavLink exact activeClassName="active" to="/">
Home
</NavLink>
</li>
<li>
<NavLink exact activeClassName="active" to="/about">
About
</NavLink>
</li>
<li>
<NavLink exact activeClassName="active" to="/contact">
Contact
</NavLink>
</li>
</ul>
</nav>
)
As a side note: You should Never combining jQuery with React
Here is a live example at codeSandbox
Since you need to highlight parent element of link (li) you can use withRouter (or useLocation hook for functional components) with NavLink from react-router in NavigationBar:
import React, { Component } from 'react';
import { withRouter } from 'react-router';
class NavigationBar extends Component {
constructor(props) {
super(props);
this.renderMenuLink = this.renderMenuLink.bind(this);
}
componentDidMount() {
toggleIcon();
}
renderMenuLink({ path, label }) {
const { location } = this.props;
const isActive = location.pathname === path;
return (
<li key={path} className={`nav-item ${isActive ? 'active' : ''}`}>
<NavLink className="nav-link" to={path}>
{label}{isActive ? <span className="sr-only">(current)</span> : ''}
</NavLink>
</li>
);
}
render() {
const menuLinks = [
{ path: '/', label: 'Home' },
{ path: '/form', label: 'Submit Form' },
{ path: '/register', label: 'Sign Up' },
{ path: '/login', label: 'Login' },
];
return (<div id="topheader">
<nav className="navbar navbar-expand-lg navbar-light bg-light ">
<a className="navbar-brand" href="#">Whatever</a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav nav nav-pills ml-auto">
{menuLinks.map((menuLink) => this.renderMenuLink(menuLink))}
</ul>
</div>
</nav>
</div>
)
}
}
export default withRouter(NavigationBar);

Adding Active class to react sidebar

I am trying to add 'active' as className to my each in sidebar component. What I want is that whichever gets activated, it should attach class 'active' to it and then set CSS accordingly.
I tried using react-router location props referring to this SO answer: https://stackoverflow.com/a/42766792/11349591, but unable to follow the syntax/result properly.
Here is my code for Sidebar.js
import React, {Component} from 'react'
import { NavLink, Link } from 'react-router-dom'
import '../../css/active.css';
export default function SideBar(){
const { location } = this.props;
const dashboardClass = location.pathname === "/" ? "active" : "";
const userClass = location.pathname.match(/^\/user/) ? "active" : "";
const listClass = location.pathname.match(/^\/list/) ? "active" : "";
return (
<div style={{flexBasis: '200px', backgroundColor: 'gray'}}>
<nav style={{textAlign:'left'}}>
<ul className="side-bar">
<li className={dashboardClass}>
<i class="fa fa-pie-chart fa-2x" aria-hidden="true" style={{color:'#ccc'}}></i>
<Link to="/dashboard">
Dashboard
</Link>
</li>
<li className={userClass}>
<i class="fa fa-user-circle fa-2x" aria-hidden="true" style={{color:'#ccc'}}></i>
<Link to="/user" >User</Link>
</li>
<li className={listClass}>
<i class="fa fa-list-alt fa-2x" aria-hidden="true" style={{color:'#ccc'}}></i>
<Link to="/list">Table List</Link>
</li>
</ul>
</nav>
</div>
)
}
App.js (Home component render Sidebar and Dashboard component)
function App() {
return (
<div className="App">
<Switch>
<Route exact path="/" component={Home} />
<Route path="/register" component={Register} />
<Route path="/login" component={Login} />
</Switch>
</div>
);
}
Home.js
export default class Home extends Component {
render() {
return (
<div style={{display: 'flex', flexDirection: 'row'}}>
<SideBar/>
<Dashboard/>
</div>
)
}
}
My console report this problem: TypeError: Cannot read property 'props' of undefined
You are trying to access this.props from a functional component and that's only possible in class based components. Change your code to this:
export default function SideBar({ location }){
// Rest of the code
You also need to pass the router props down from Home to Sidebar component:
export default class Home extends Component {
render() {
return (
<div style={{display: 'flex', flexDirection: 'row'}}>
<SideBar {...this.props}/> // Pass the props down
<Dashboard/>
</div>
)
}
}
To activate the Nav link you should use NavLink instead of Link. NavLink has one property called activeClassName, you should apply that class to it. let say if you have class called active which you want to apply after clicking on that then you can do this.
<NavLink to="/user" activeClassName={classes.active}>
<li className={dashboardClass}>
<i class="fa fa-pie-chart fa-2x" aria-hidden="true" style={{color:'#ccc'}}></i>
</li>
</NavLink>

Resources