Want to Re-render an other component in React JS - javascript

Actually I want another component to Re-render if some changes are made in some other component, parent of both component contain some other component that I don't want them to Re-render. just want when the function is executed it went back to parent and only Re-render the specific component. can't use Window.location.reload because it refresh all the items anything that can rerender only the triggered component. following code is just meant for the idea. as changes are done in First it must be reflected in the other component
`
{/* Parent Component*/}
class Parent extends React.Component {
constructor() {
super();
this.state = {
}
}
render() {
return (
<>
<SecondComponent />
<firstComponent />
<anotherComponent />
<anotherComponent />
<anotherComponent />
</>
);
}
}
export default Parent;
{/* 1 child component */}
import { React } from "react";
const FirstComponent = () => {
const handleChange=(event) =>{
const {name, value}=event.target
localStorage.setItem(name, value)
}
return (
<>
<div className="container-fluid">
<div className="row">
<div className="col-11 col-md-10 mx-auto">
<h1>All Searches</h1>
<input type='text' name='tab1' onChange={handleChange} />
<input type='text' name='tab2' onChange={handleChange} />
</div>
</div>
</div>
</>
);
}
export default FirstComponent;
{/* 2nd Child Component */}
import React from 'react';
import { NavLink } from 'react-router-dom'
class SecondComponent extends React.Component {
constructor(){
super();
this.state={
tab1:localStorage.getItem("tab1"),
tab2:localStorage.getItem("tab2"),
}
}
render() {
return (
<>
<div className="d-inline-flex" style={{ background: "#242F84", width: "100%" }}>
<NavLink to="/" className="Home">
<p className="mb-0 FS_28 px-2 White" >Home</p>
</NavLink>
<NavLink to="/AllSearches">
<p className="mb-0 White">All Searches</p>
</NavLink>
<NavLink to="/AllSearches">
<p className="mb-0 White">{this.state.tab1}</p>
</NavLink>
<NavLink to="/AllSearches">
<p className="mb-0 White">{this.state.tab2}</p>
</NavLink>
</div>
</>
);
}
}
export default SecondComponent;
`

To re-render a component the standard way is to change its state. The question is - If a component's state is not changed, why would you want to re-render it?
I see you are using local storage - I suggest you use local state as much as you can in stead of local storage to manage this type of information.

Related

Cannot read property 'map' of undefined in MenuComponent

I'm new to React. I'm building up an app in which MainComponent is the container component and MenuComponent and DishDetail are the presentation components.
When I'm running the code in the browser it is showing cannot read property 'map' for undefined in MenuComponent at line 11.
I have checked it and have done it as instructed in my lecture but still facing this problem. I'm attaching all the files here :
MainComponent:
import React, { Component } from 'react';
import { Navbar, NavbarBrand } from 'reactstrap';
import Menu from './MenuComponent';
import DishDetail from './DishdetailComponent';
import { DISHES } from '../shared/dishes';
class Main extends Component {
constructor(props) {
super(props);
this.state = {
dishes: DISHES,
selectedDish : null
};
}
onDishSelect(dishId) {
this.setState({ selectedDish: dishId});
}
render() {
return (
<div>
<Navbar dark color="primary">
<div className="container">
<NavbarBrand href="/">Ristorante Con Fusion</NavbarBrand>
</div>
</Navbar>
<Menu dishes={this.state.dishes} onClick={(dishId) => this.onDishSelect(dishId)} />
<DishDetail selectedDish={this.state.dishes.filter((dish) => dish.id === selectedDish(dishId))[0]} />
</div>
);
}
}
export default Main;
MenuComponent :
import React, { Component } from 'react';
// import { Media } from 'reactstrap';
import { Card, CardImg, CardImgOverlay, CardText, CardBody,CardTitle } from 'reactstrap';
class Menu extends Component {
constructor(props) {
super(props);
}
render() {
const menu = this.props.dishes.map((dish) => {
return(
<div key={dish.id} className="col-12 col-md-5 m-1">
{/* <Media tag="li">
<Media left middle>
<Media object src={dish.image} alt={dish.name} />
</Media>
<Media body className="ml-5">
<Media heading>{dish.name}</Media>
<p>{dish.description}</p>
</Media>
</Media> */}
<Card key={dish.id} onClick={() => this.props.onDishSelect(dish.id)}>
<CardImg width="100%" src={dish.image} alt={dish.name} />
<CardImgOverlay>
<CardTitle>{dish.name}</CardTitle>
</CardImgOverlay>
</Card>
</div>
);
});
return(
<div className="container">
<div className="row">
{/* <Media list>
{menu}
</Media> */}
{menu}
</div>
</div>
);
}
}
export default Menu;
That's basically saying that the value from this.props.dishes is undefined.
Make sure that the value that you're importing below is an array (and it's valid).
import { DISHES } from '../shared/dishes';
Also, you can use the DISHES variable directly instead of storing it into the state, like this:
<Menu dishes={DISHES} onClick={(dishId) => this.onDishSelect(dishId)} />

React Hide/Show Menu on Successful Login and Passing Information from one Component to a Component

Total Newbie in React and most of my learning is done through experimentation.
I have the following components:
App.js
import React, { Component } from 'react';
// Libraries and Utilities
import { BrowserRouter, Switch, Route } from 'react-router-dom';
// Components
import Layout from './components/layout/Layout';
import Home from './components/home/Home';
import Login from './components/login/Login';
class App extends Component {
static displayName = App.name;
render() {
return (
<BrowserRouter basename='/myapp>
<Layout>
<Switch>
<Route path="/" exact component={Home} />
<Route path='/login' component={Login} />
<Route path='/admin' component={Admin} />
</Switch>
</Layout>
</BrowserRouter>
);
}
}
export default App;
Layout.js
import React, { Component } from 'react';
import NavMenu from '../navigation/NavMenu';
class Layout extends Component {
render() {
return (
<div className="container-fluid">
<div className="row">
<NavMenu />
</div>
<div className="main layout">
{this.props.children}
</div>
<div className="row">
<Footer />
</div>
</div>
);
}
};
export default Layout;
NavMenu.js
import React, { Component } from 'react';
import { NavLink } from "react-router-dom";
import logo from '../../assets/logo.svg';
class navigation extends Component {
constructor(props) {
super(props)
this.state = {
loggedIn: false
}
}
render() {
return (
<div className="row">
<nav className="navbar navbar-expand navbar-dark bg-primary fixed-top">
<a className="navbar-brand" href="/">
<img src={logo} width="250" height="70" alt="" />
</a>
<div className="collapse navbar-collapse">
<ul className="navbar-nav mr-auto">
<li className="nav-item" to={'/'}>
<NavLink exact={true} className="navbar-brand" activeClassName='active' to='/'>Home</NavLink>
</li>
<li className="nav-item" to={'/admin1'}>
<NavLink exact={true} className="navbar-brand" activeClassName='active' to='/admin1'>Admin 1</NavLink>
</li>
<li className="nav-item" to={'/admin2'}>
<NavLink exact={true} className="navbar-brand" activeClassName='active' to='/admin1'>Admin 2</NavLink>
</li>
</ul>
<ul className="navbar-nav">
<li className="nav-item">
<NavLink exact={true} className="navbar-brand" activeClassName='active' to='/login'>
<i className="fa fa-sign-in" aria-hidden="true"></i>
</NavLink>
</li>
</ul>
</div>
</nav>
</div>
)
};
};
export default navigation;
Login .js
import React, { Component } from 'react';
class login extends Component {
constructor(props) {
super(props)
this.state = {
loginModel: {
UserName: '',
Password: ''
}
}
this.handleInputChange = this.handleInputChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleInputChange(event) {
const target = event.target
const value = target.type === 'checkbox' ? target.checked : target.value
const name = target.name
this.setState(prevState => ({
loginModel: {
...prevState.loginModel,
[name]: value
}
}))
}
handleSubmit(event) {
// At This Stage, I perform an API Call (via axios) and I get the Response Data.
const url = 'some url'
axios.post(url, this.state.loginModel).then((response) => {
if (response.status === 200) {
// Get token from response to be used in authenticated api calls.
const responseData = response.data
let authToken = responseData.token
console.log('authToken', authToken)
swal({
title: "My Application",
text: "Logon Successful.",
icon: "success"
}).then((value) => {
// Go to the Admin Home.
const path = '/admin'
this.props.history.push(path);
})
}
}, (err) => {
console.log(err.response)
const msg = err.response.data.message
const icon = err.response.data.icon
swal({
title: "My Application",
text: msg,
icon: icon
})
})
)
event.preventDefault();
}
componentDidMount() {
}
render() {
return (
<form className="form-signin" onSubmit={this.handleSubmit} >
<h3>Sign In</h3>
<div className="form-group">
<label>Username</label>
<input type="text" className="form-control" autoComplete="off"
id="input-username" name="UserName"
value={this.state.loginModel.UserName}
onChange={this.handleInputChange}
placeholder="Enter Username" />
</div>
<div className="form-group">
<label>Password</label>
<input type="password" className="form-control" autoComplete="off"
id="input-password" name="Password"
value={this.state.loginModel.Password}
onChange={this.handleInputChange}
placeholder="Enter Password" />
</div>
<button type="submit" className="btn btn-primary btn-block">Submit</button>
</form>
)
}
}
export default login;
Home.js
import React from 'react';
import { NavLink } from "react-router-dom";
const home = (props) => {
return (
<div className="container-fluid">
<div className="fill">
<div className="row">
<div className="col-md-4 col-sm-12">
<div className="card">
<div className="card-body flex-fill">
<h5 className="card-title">Info 1</h5>
<p className="card-text">
Details about Info 1
</p>
</div>
<div className="card-footer">
<NavLink exact={true} className="btn btn-primary btn-block" to='/info1'>Start</NavLink>
</div>
</div>
</div>
<div className="col-md-4 col-sm-12">
<div className="card">
<div className="card-body flex-fill">
<h5 className="card-title">Info 2</h5>
<p className="card-text">
Details about Info 2
</p>
</div>
<div className="card-footer">
<NavLink exact={true} className="btn btn-info btn-block" to='/info2'>Browse</NavLink>
</div>
</div>
</div>
<div className="col-md-4 col-sm-12">
<div className="card">
<div className="card-body flex-fill">
<h5 className="card-title">Info 3</h5>
<p className="card-text">
Details about Info 3
</p>
</div>
<div className="card-footer">
<NavLink exact={true} className="btn btn-success btn-block" to='/info3'>View</NavLink>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default home;
My approach is quite simple. The application shows the Home component on initial load.
In the Navmenu, I have a link that navigates me to the Login screen.
In the Login screen, I have a login form where I am able to validate the user name and password via an API call.
I have multiple questions as I am still learning, but adding them here altogether as I feel it is all related.
Questions:
In my NavMenu component, I want to hide the admin1 and admin2 when on
initial load, and show it when the login is successful in the Login
component.
I want to prevent user from going to the route /admin1 and
/admin2 unless they are logged in. I am trying to read Protected
Routes but I am unable to get the hang of it as of yet.
In my Login screen, after successful login, one of the return value of the API
call is an API Key I can use for authorized calls. How can I make
that available such that I can access it from anywhere I perform an
API call.
I hope I provided enough context on what I am trying to achieve here. I know I need to brush up further my skills on how data communication between React happens.
Update: Been reading about Hooks, but I am unsure how to implement it here. Would I need to convert my JS files to use functional approach rather than class structure (ES6)?
Gracias.
I use redux for checking if use if logged in or not.
So when app start before show anything I check this.
and then I have privateRoute.
import React from "react";
import { Redirect, Route } from "react-router-dom";
import { useSelector } from "react-redux";
function PrivateRoute({ component: Component, ...props }) {
const isAuthenticated = useSelector(state => state.User.isLogin);
return (
<Route
render={props =>
isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
{...props}
/>
);
}
export default PrivateRoute;
and define IsAuthenticated component to redirect home page if user is already logged in:
import React from "react";
import { Redirect, Route } from "react-router-dom";
import { useSelector } from "react-redux";
function IsAuthenticated({ component: Component, ...props }) {
const isAuthenticated = useSelector(state => state.User.isLogin)
return (
<Route
{...props}
render={props =>
!isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/",
state: { from: props.location }
}}
/>
)
}
/>
);
}
export default IsAuthenticated;
and define my routes here if user must authenticated to see them:
<Router>
<Switch>
{privateRoutes.map(({ path, component: Component }, idx) => (
<PrivateRoute
key={idx}
exact
path={path}
component={() => (
<SideNav>
<Component />
</SideNav>
)}
/>
))}
<IsAuthenticated exact path="/login" component={LoginPage} />
</Switch>
</Router>
here I use SideNav in my pages, you can use redux state in your Navbar component and with checking that you can show or hide whatever you want.
Or you can define two layout for your two types of your pages.
If you don't want to use redux, you can define state in App.js and pass it to your component or use react context.
I hope I helped you in your question.

Rendering nested router view without parent router view - React.js

Hello community :) My first Q here.
(There were couple of similar questions but they didn't answer my particular code issue and I tried them to apply but without success.)
So I would like to render the child component in nested route without the parent one showing in the view
See the picture at the end --->
import React from 'react';
import {BrowserRouter, Route, Switch, Link} from "react-router-dom";
import 'bootstrap/dist/css/bootstrap.min.css';
import Routing from "./components/Routings";
export default class Browserrouting extends React.Component {
render () {
return (
<BrowserRouter>
<Routing/>
</BrowserRouter>
)
}
}
Here is the Routing component :
import About from "../views/About";
import HomeBackground from "../views/Background";
import ShelterApp from '../views/ShelterApp';
export default (props) => (
<div className="flexColumn">
<div> <ul className="flexRow center">
<li className="homeLink"><Link className="colorBrown" to="/">Home</Link></li>
<li className="homeLink"><Link className="colorBrown" to="/shelterApp">Shelter App</Link></li>
<li className="homeLink"><Link className="colorBrown" to="/about">About our site and shelter</Link></li>
</ul></div>
<Switch>
<Route exact path="/" component={() => <HomeBackground />} />
<Route path="/about" component={() => <About />} />
<Route path="/shelterApp" component={() => <ShelterApp />} />
</Switch>
</div>
)
And in ShelterApp component I have some text and imported another component which contains the links and nested routes I would like to display without showing the parent component ShelterApp:
class ShelterApp extends React.Component {
render() {
return (
<div className="flex center">
<div className="card center" style={{ "width": "25em", "height":"25em" }}>
<div className="card-body textCenter">
<h5 className="card-title paddingTitle">Welcome to our site</h5>
<h6 className="card-subtitle mb-2 text-muted"> Login or register if it's your first time</h6>
</div>
<LoginRouting match={this.props.match} />
</div>
</div>)
}
}
export default ShelterApp;
and the final child componet with the "lowest" routes in hierarchy :
class LoginRouting extends React.Component {
constructor(props) {
super(props)
this.state = {
users: []
}
}
static propTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
};
render() {
const { match, location, history } = this.props;
return (
<div >
<div className="flexRow center">
<Button className={" loginRouting"} type={"button"} bootstrapClass={"btn btn-light"} child={<Link to="/shelterApp/login">Login form</Link>} />
<Button className={" loginRouting"} type={"button"} bootstrapClass={"btn btn-light"} child={<Link to="/shelterApp/register">Register form</Link>} />
</div>
<div>
<Route path="/shelterApp/login" render={() => <Login />} />
<Route path="/shelterApp/register" render={() => <Register />} />
</div>
</div>
)
}
}
export default withRouter( LoginRouting)
enter image description here
IMAGE with the view :
I will be thankful for any advises !
On your ShelterApp component you can create a new state called hideInfo, or something, that tracks if the user clicked on "Login form" or "Register form".
Then you can pass a props to your <LoginRouting> component.
When the user clicks on "Login form" or "Register form" you change this.hideInfo.
<LoginRouting
onShowForm={() => this.setState({ hideInfo: !hideInfo})}
match={this.props.match}
/>

How to pass a react component trough a parent?

I have an App component witch contains two child: A navbar and a container.
When I click on a li on the navbar I'm passing a react component trough the parent, but it doesen't wrok.
App:
function App() {
const [appState, setAppState] = useState();
useEffect(() => {
console.log(appState);
}, [appState])
return (
<div className="App">
<Nav stateSetter={setAppState}/>
<Container state={appState}/>
</div>
);
}
Navbar:
function Nav(props) {
return (
<div>
<div className="Nav" id="nav">
<nav>
<ul>
<li><button><span>App</span></button></li>
<li><button onClick={() => props.stateSetter("")}>Home</button></li>
<li><button onClick={() => props.stateSetter("")}>Products</button></li>
<li><button onClick={() => props.stateSetter("")}>About Us</button></li>
<li><button onClick={() => props.stateSetter(<Login />)}>Log in</button></li>
</ul>
</nav>
</div>
</div>
);
}
I only made the passing with the Login.
Container:
function Container(props) {
const [renders, setRenders] = useState(props.state);
console.log(renders);
return (
<div>
<div className="container">
{renders}
</div>
</div>
);
}
State is preserved for the "same" component across renders, which is its primary purpose. When you do a useState, you can pass the initial value for your state, but that state can henceforth only be changed with the setState function. So on first render, your Container has renders set to undefined (the initial property value passed by the parent). When this props.state prop is passed in later on, it's not going to change your state.
You should consider not using state in Container for this and allow the parent to control it; if Container needs the prop to change, you can use a callback instead:
function Container({ state: content }) {
return (
<div>
<div className="container">
{content}
</div>
</div>
);
}
react has a built in prop for passing components to Children props.children
you can pass a component to this prop as so
<Child><h1>passing text</h1></Child>
And you can access this from the Child like so
return (
<div>{props.children}</div>
)
Although the other answers address your problem, passing around components to navigate through your app would become messy and difficult to build on top of. Another approach that you should consider is using React Router which handles the rendering of components for you.
With this package, your code would look something like this:
App:
// Node Modules
import React from 'react';
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
// Page Components
import Home from './Home';
import About from './About';
import Products from './Products';
import Login from './Login';
function App() {
const [appState, setAppState] = useState();
useEffect(() => {
console.log(appState);
}, [appState])
return (
<div className="App">
<Nav stateSetter={setAppState}/>
<Router>
<Route to="/" component={Home} />
<Route to="/about" component={About} />
<Route to="/products" component={Products} />
<Route to="/login" component={Login} />
</Router>
</div>
);
}
Navbar:
// Node Modules
import {Link} from 'react-router-dom'
function Nav(props) {
return (
<div>
<div className="Nav" id="nav">
<nav>
<ul>
<li><button><span>App</span></button></li>
<li><Link to="/">Home</Link></li>
<li><Link to="/products">Products</Link></li>
<li><Link to="/about">About Us</Link></li>
<li><Link to="/login">Login</li>
</ul>
</nav>
</div>
</div>
);
}
This will remove the need for you container component and will allow you to organize your page components in a way that is easier to develop on. It will also remove the need to have an useState() in your App component to keep track of your page components.

Most basic way to execute ReactJs server side rendering

I want to make a very basic reactjs based application with server-side rendering to make sure the first load is quick and also to make sure all crawlers can access my content.
For this, I first followed the official reactjs docs and then looked for a basic routing option for my need. I ended up using React Router. Now, I want to enable server-side rendering for it without having to completely change this to use Redux or something. What would be the most basic/simplest way to do this.
The code in its present condition is as below:
import React from 'react'
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
import './index.css';
//Product Image Component
class ProductImage extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 'https://rukminim1.flixcart.com/image/832/832/j8bxvgw0-1/mobile/g/j/z/mi-mi-mix-2-na-original-imaeydgnjzmvxwfz.jpeg?q=70',
alt: 'the product image'
};
}
render() {
return (
<div className="ProductImageContainer">
<img className="ProductImage"
src={this.state.value}
alt={this.state.alt}
/>
</div>
);
}
}
//Single Product Component
class ProductSingle extends React.Component {
render() {
return (
<div className="single">
<ProductImage />
</div>
);
}
}
//Homepage
class Home extends React.Component {
render() {
return (
<div>
<h2>Home</h2>
<p>The content is here.</p>
</div>
);
}
}
//About Page
class About extends React.Component {
render() {
return (
<div>
<h2>About</h2>
<p>The content is here.</p>
</div>
);
}
}
//Topic component
class Topic extends React.Component {
render() {
const {match} = this.props;
return (
<div>
<h3>{match.params.topicId}</h3>
</div>
);
}
}
//Topics component
class Topics extends React.Component {
render() {
const {match} = this.props;
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/rendering`}>
Rendering with React
</Link>
</li>
<li>
<Link to={`${match.url}/components`}>
Components
</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
<Route path={`${match.url}/:topicId`} component={Topic}/>
<Route exact path={match.url} render={() => (
<h3>Please select a topic.</h3>
)}/>
</div>
);
}
}
//Main App component
class App extends React.Component {
render() {
return (
<Router>
<div>
<ul className="menu">
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/topics">Topics</Link></li>
</ul>
<Route exact path="/" component={Home}/>
<Route path="/about" component={ProductSingle}/>
<Route path="/topics" component={Topics}/>
</div>
</Router>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
https://github.com/gzoreslav/react-redux-saga-universal-application/blob/master/README.md please check my repo. I used redux and redux-saga, but I guess you may replace them with another flux that you need

Categories