How to link on click function to another component in React app? - javascript

I have a landing page that contains a logo. I'm trying to get this logo to trigger a change of of state value. The purpose of this is to change from the landing page to the home page on click. I have set it up so that the landing page clear in an determined time, but I want to do this on click. This is my splash.js file that contains the on click function as well as the logo and landing page:
import React, { Component } from 'react';
import Woods from './woods.jpeg';
import Logo1 from './whitestar.png';
export default class Splash extends Component {
constructor() {
super();
this.toggleShowHome = this.toggleShowHome.bind(this);
}
toggleShowHome(property){
this.setState((prevState)=>({[property]:!prevState[property]}))
}
render() {
return(
<div id='Splashwrapper'>
<img src={Woods}></img>
<img id='logoc' src={Logo1} onClick={()=>this.toggleShowHome('showSquareOne')}></img>
</div>
);
}
}
I want the on click function to change the value of splash to false in my App.js file:
import React, { Component } from 'react';
import Splash from './splash';
import Menu from 'components/Global/Menu';
export default class About extends Component {
constructor(){
super();
this.state = {
splash: true
}
}
componentDidMount() {
setTimeout (() => {
this.setState({splash: false});
}, 10000);
}
render() {
if (this.state.splash) {
return <Splash />
}
const { children } = this.props; // eslint-disable-line
return (
<div className='About'>
<Menu />
{ children }
</div>
);
}
}
How can I link the on click function to the App.js file and change the value of splash?

You should define your function toggleShowHome in app.is and pass it as a prop to your splash component. Then you could change your local state in app.js

To make sure I'm understanding, you're looking for the image on the Splash component to trigger a change in the About component?
You can pass a method to your Splash component (from About) that it can call when the image is pressed. So something like this:
render() {
if(this.state.splash) {
return <Splash onLogoClicked={this.logoClicked.bind(this)} />
}
(.......)
}
logoClicked(foo) {
< change state here >
}
And then in your Splash component:
<img id='logoc' src={Logo1} onClick={this.props.onLogoClicked}></img>

Not sure if I understood you well, but you can try this: to pass the on click function from parent (About) to child (Splash), something like this:
YOUR MAIN APP:
export default class About extends Component {
constructor(){
super();
this.state = {
splash: true
}
this.changeSplashState = this.changeSplashState.bind(this);
}
//componentDidMount() {
//setTimeout (() => {
//this.setState({splash: false});
//}, 10000);
//}
changeSplashState() {
this.setState({splash: false});
}
render() {
if (this.state.splash) {
return <Splash triggerClickOnParent={this.changeSplashState} />
}
const { children } = this.props; // eslint-disable-line
return (
<div className='About'>
<Menu />
{ children }
</div>
);
}
}
YOUR SPLASH COMPONENT:
export default class Splash extends Component {
constructor() {
super();
//this.toggleShowHome = this.toggleShowHome.bind(this);
}
toggleShowHome(property){
this.setState((prevState)=>({[property]:!prevState[property]}));
//IT'S UP TO YOU TO DECIDE SETTING TIMOUT OR NOT HERE
//setTimeout (() => {
this.props.triggerClickOnParent();
//}, 10000);
}
render() {
return(
<div id='Splashwrapper'>
<img src={Woods}></img>
<img id='logoc' src={Logo1} onClick={this.toggleShowHome.bind(this,'showSquareOne')}></img>
</div>
);
}
}
Feel free to post here some errors or explain to me more about what you need, but that is the way it should look like, a standard way to pass function as props from parent to child.
You can also read more about how to pass props from parent to child/grandchild/many-deeper-level-child (of course in react's way):
Force React container to refresh data
Re-initializing class on redirect

Related

Reactjs: setState from outside of component

App.js
import React from 'react';
import './App.css'
import Tools from './components/class/Tools'
import Loading from './components/inc/Loading'
export default class App extends React.Component {
componentDidMount() {
Tools.showLoading(); // or new Tools();
}
render() {
return (
<div className="App">
<Loading />
</div>
)
}
}
Loading.js:
import React from 'react'
export default class Loading extends React.Component {
constructor(props) {
super(props)
this.state = {
display: 'none'
}
}
render() {
return (
<div className="loading" style={{display: this.state.display}}>
<span></span>
</div>
)
}
}
Tools.js
export default class Tools extends React.Component {
static showLoading(){ // or non-static
Loading.setState ...
}
}
I want change display state from outside of Loading component.
I use Loading in whole my project and I want create function for handle it.
Example for another use:
function xxx(){
Tools.showLoading(); // or new Tools();
}
Or:
<span onClick={Tools.showLoading(); // or new Tools();}></span>
Actually, I want create only one function to manage and handle display of Loading.
In Tools.js
let loadingStateSetter = null
export function setLoadingStateSetter(setter) {
loadingStateSetter = setter
return () => loadingStateSetter = null
}
export function setLoadingState(value) {
if (loadingStateSetter !== null) loadingStateSetter(value)
}
In Loading.js:
import { setLoadingStateSetter } from './Tools.js'
export default class Loading extends React.Component {
constructor(props) {
super(props)
this.state = {
display: 'none'
}
}
render() {
return (
<div className="loading" style={{display: this.state.display}}>
<span></span>
</div>
)
}
componentDidMount() {
this.removeStateSetter = setLoadStateSetter((value) => {
this.setState((state) => ({
...state,
display: value,
})
})
}
componentWillUnmount() {
this.removeStateSetter()
}
}
Usage:
import { setLoadingState } from './Tools.js'
function xxx(){
setLoadingState('some value')
}
While you can easily expose a setState function externally, it acts just like any other function, its not usually a good idea. You should instead consider rewriting your Loading component to use the property object to tell it if its loading and track the loading state higher up the component tree where it is accessible by things that would want to change its status.
I think you can using redux as store manager global state
https://redux.js.org/
another way pass it through props and handle it at parent component

Switch child components by state

I have a parent component:
import React, { Component, Fragment } from "react";
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
SignUpClicked: null
};
this.openSignUp = this.openSignUp.bind(this)
}
openSignUp() {
this.setState({
SignUpClicked: true
})
console.log('signup clicked')
}
render() {
return (
<div>
<SignUp
authState={this.props.authState}
onStateChange={this.props.onStateChange}
openSignUp = {this.openSignUp} />
<SignIn
authState={this.props.authState}
onStateChange={this.props.onStateChange} />
</div>)
}
}
export default Parent;
and then two child components SignUp & SignIn in different files.
In each of them there's a link like <p>Sign Up Instead?<a href="#" onClick = {this.props.openSignUp}> Sign Up </a></p> and the other way for Sign In.
However, I can't get them to switch between the two components - what am I doing wrong here?
You can easily control which component should be rendered by putting condition with them. If this.props.authState is true, show SignUp component else show SignIn component
<div>
{!this.props.authState && (<SignUp
authState={this.props.authState}
onStateChange={this.props.onStateChange}
openSignUp = {this.openSignUp} />) }
{this.props.authState && (<SignIn
authState={this.props.authState}
onStateChange={this.props.onStateChange} />)}
</div>
There is a concept called conditional rendering you can use that can solve your problem. Simply put in conditional rendering you display a component only when a condition is met. In your case, you can try the following.
import React, { Component, Fragment } from "react";
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
SignUpClicked: false
};
}
//changed this to arrow function that binds "this" automatically
toggleSignUp = () => {
this.setState({
SignUpClicked: !this.state.SignUpClicked
})
console.log('signup clicked')
}
render() {
return (
<div>
{ this.state.SignUpClicked &&
<SignUp
authState={this.props.authState}
onStateChange={this.props.onStateChange}
openSignIn = {this.toggleSignUp} />
}
{!this.state.SignUpClicked &&
<SignIn
authState={this.props.authState}
onStateChange={this.props.onStateChange}
openSignUp = {this.toggleSignUp} />
/>
}
</div>
)}
}
export default Parent;
NOTE: Pay attention to the changes I have done
Changed the function to arrow function by using them you don't have to bind this in constructor. It automatically does that for you.
I have changed the name of function openSignUp to toggleSignUp because we will use a single function to display signup component and than hide it if we want. (because I assume you will implement "sign in instead" in <SignUp/> component to get back to sign in
I have passed the same toggleSignUp function reference to both the components so that you can show or hide either of them.
Do it this way
import React, { Component, Fragment } from "react";
class Parent extends Component {
constructor(props) {
super(props);
// Set state of the component
this.state = {
// Show sign in page by default
show: "signin"
};
}
showSignup = () => {
// Show sign up page by changing the show variable
this.setState({
show: "signup"
});
console.log('Showing Signup Page');
}
showSignin = () => {
// Show sign in page by changing the show variable
this.setState({
show: "signin"
});
console.log('Showing Signin Page');
}
render() {
// Render the component as per show state variable
if(this.state.show === "signin") {
return <SignIn
authState={this.props.authState}
onStateChange={this.props.onStateChange}
onSignup={this.showSignup}
/>
}
else {
return <SignUp
authState={this.props.authState}
onSignup={this.showSignin}
/>
}
}
export default Parent;
So basically, export onClick event from both the child components and set show variable of state in parent component. Then depending upon the state, return only the component you want.
Please let me know if there is any question or confusion. Would love to answer.

How do I reveal my button only when on a specific component?

I want to show the Logout button on the same row of the title but only when the user has made it to Home component.
In other words, I don't want to show the logout button at all times, especially when the user's at the login screen. I want it to show on the same row of the title only when they've logged in successfully and they're in Home
How would I achieve this? My head hurts from trying to make this work :(
Below's what I've tried so far, among other things.
import React, {Component} from 'react';
import classes from './Title.css';
import LogoutButton from '../../containers/LogoutButton/LogoutButton';
import Home from '../../components/Home/Home';
class Title extends Component {
constructor(props) {
super(props);
this.state = {
show: false,
showLogoutButton: true
};
}
showButton() {
this.setState({show: true});
if(this.state.show) {
return <LogoutButton/>;
} else {
return null;
}
}
render() {
return(
<div>
{ this.state.showLogoutButton ? this.showButton : null }
<h1 className={classes.Title}>Pick Ups</h1>
</div>
);
}
}
export default Title;
You can try something like below. You don't need to deal with function and modifying states.
You can simply do like below
import classes from './Title.css';
import LogoutButton from '../../containers/LogoutButton/LogoutButton';
import Home from '../../components/Home/Home';
class Title extends Component {
constructor(props) {
super(props);
this.state = {
showLogoutButton: this.props.authenticated
};
}
render() {
const { showLogoutButton } = this.state;
return(
<div className="row" style={{"display" :"flex"}}>
{ showLogoutButton && <LogoutButton/>}
<h1 className={classes.Title}>Pick Ups</h1>
</div>
);
}
}
export default Title;
Note: When you modify state using setState the state value will be updated only after render so you can't directly check immediately modifying the value.

How to add a status minipage in reactjs?

I am building a web front-end and I want to have the same status minipage running on each page of my website. This is what I have so far
export default class Status extends Component {
constructor(props) {
super(props);
this.state = {
// some features
};
}
recheck = event => {
// some status check
}
componentDidMount() {
this.interval = setInterval(() => this.check(), 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<div className="Status">
{/*... some status */}
</div>
);
}
}
and I'd hope to have such component always rendered. Is there any way to do so?
Here is some sample code on how to include your Status component within App.js
Edit: Per your comment I've included some examples of passing props to <Status/>
// App.js
import React, { Component } from 'react';
import Status from './Status'; // Status.js
class App extends Component {
render() {
const bar = "World";
return {
<div className="App">
...some layout
<Status foo="Hello" bar={bar}/>
</div>
}
}
}

Conditional Rendering not reliably setting state on different components

I have two navigation buttons (light version, and dark version) that I want to render on certain pages.
I tried setting the state in the constructor, and generating the link to the images based on the path of the page, but sometimes the wrong link to the image will generated. It seems as though it's getting the state based on the first page that was ever generated. For example, if "home" is supposed to have the light version of the button any other link I click will generate the light version of the logo, unless I refresh. If "about" is supposed to have the dark version of the logo, all other pages I click through will have the dark version, unless I refresh.
Why won't it generate properly while naturally clicking around and navigating through the different pages?
MenuButton.js
import React, { Component } from 'react';
export default class MenuButton extends Component {
constructor() {
super();
this.state = {
logo_url: ''
}
}
componentDidMount() {
let currentPath = window.location.pathname;
if (!currentPath.includes('about') && !currentPath.includes('news')
&& !currentPath.includes('work')) {
this.setState({ logo_url: `${require('../../assets/nav/logo-light.svg')}` });
} else {
this.setState({ logo_url: `${require('../../assets/nav/logo-dark.svg')}` });
}
}
render() {
return (
<div className="menu-btn--cntr">
<img src={this.state.logo_url} />
</div>
)
}
}
You don't need to use state and life cycle.
You can try something like below -
import React, { Component } from 'react';
export default class MenuButton extends Component {
constructor() {
super();
this.state = {
logo_url: ''
}
}
getButton() {
let currentPath = window.location.pathname;
let btnUrl = ''; // or set some default
if (!currentPath.includes('about') && !currentPath.includes('news')
&& !currentPath.includes('work')) {
// this.setState({ logo_url: `${require('../../assets/nav/logo-light.svg')}` });
btnUrl = `${require('../../assets/nav/logo-light.svg')}`;
} else {
// this.setState({ logo_url: `${require('../../assets/nav/logo-dark.svg')}` });
btnUrl = `${require('../../assets/nav/logo-light.svg')}`;
}
return btnUrl;
}
render() {
const btnUrl = this.getButton();
return (
<div className="menu-btn--cntr">
<img src={btnUrl} />
</div>
)
}
}

Categories