reactjs call specific function when page refreshed or closed - javascript

I have a component like:
import React, { PropTypes, Component } from 'react'
class MyView extends Component {
componentDidMount() {
window.addEventListener('onbeforeunload', this.saveState())
}
componentWillUnmount() {
window.removeEventListener('beforeunload', this.saveState())
}
saveState() {
alert("exiting")
}
render() {
return (
<div>
Something
</div>
)
}
}
export default MyView
Here when a user refresh the page I want to call a specific funtion and when call is finished I want the page to be refreshed. Same when user closes the page.
In my above code I am adding an event listener onbeforeunload and calling a saveState function.
But here my componentDidMount is working normally. onbeforeunload and saveState function is called normally when page is loaded not when page is refreshed or exited.
What is wrong in here and how can I call specific funcitn or give alert when someone exits or refresh the page in react ?
In the above code

Attach beforeunload event on top level component and on beforeunload event make render empty which will trigger componentWillUnmount of all child components.
import React, { PropTypes, Component } from 'react'
class App extends Component {
componentDidMount() {
window.addEventListener('beforeunload', () =>{
this.setState({appended:true});
});
}
render() {
if(this.state.appended){
return false;
}else{
return (<MyView />)
}
}
}
class MyView extends Component {
componentWillUnmount() {
this.saveState()
}
saveState() {
alert("exiting")
}
render() {
return (
<div>
Something
</div>
)
}
}
export default MyView
Hope this work for you.

According to this, try this syntax :
componentDidMount() {
window.addEventListener('onbeforeunload', this.saveState)
}
componentWillUnmount() {
window.removeEventListener('beforeunload', this.saveState)
}

Related

why onclicking only the onclick function working

import React, { Component } from 'react';
import { OverlayCartContainer,OverlayCartHeader,TotalContainer,
ActionSection,ViewBagButton,CheckoutButton,OverlayContainerWrapper,} from './OverlayCartStyle';
import { Link } from 'react-router-dom'
import { connect } from 'react-redux';
import { OverlayCartbody } from '../../';
export class OverlayCartWrapperContainer extends Component {
constructor(){
super();
this.state={
ref: React.createRef(null),
actionRef: React.createRef(null),
}
}
render() {
return (
<OverlayContainerWrapper > <OverlayCartContainer ref={this.state.ref}>
<OverlayCartHeader>
My Bag,   <span>{getTotalItem()} items</span>
</OverlayCartHeader>
<OverlayCartbody cartItem ={this.props.cart}/>
<TotalContainer>
<p>Total</p>
<h6>{this.props.currencySymbol} {getTotalPrice(this.props.currencyState)}</h6>
</TotalContainer>
<ActionSection >
<Link to={"/cart"}><ViewBagButton onClick={(e)=>{this.props.toggleCart(e)}}>VIEW BAG</ViewBagButton></Link>
<CheckoutButton>CHECKOUT</CheckoutButton>
</ActionSection>
</OverlayCartContainer></OverlayContainerWrapper>
)
}
}
const mapStateToProps = (state) =>{
return {
currencyState:state.currency.currencyState,
currencySymbol:state.currency.currencySymbol,
cart:state.cart.cart.cartItems
}
}
export default connect(mapStateToProps)(OverlayCartWrapperContainer);
Here in the <ActionSection ><Link to={"/cart"}><ViewBagButton onClick={(e)=>{this.props.toggleCart(e)}}>VIEW BAG</ViewBagButton></Link<CheckoutButton>CHECKOUT</CheckoutButton></ActionSection>
I want when i click on view bag it redirect to cart view page it should go to cart page but the onclick function is rendering . i also want that onclick function run but page also redirect please help me how to do it this onClick={(e)=>{this.props.toggleCart(e)}} onclick should run but it also go to the next page
Is your App/Component wrapped in react-router? if not don't use Link.
Simple solution i can think of is replace your Link with div and then your onClick function will work and in the end of onClick function code, you can use history.push('/cart')
<div>
<ViewBagButton onClick={this.props.toggleCart}>
VIEW BAG
</ViewBagButton>
</div>
const toggleCart = (e) => {
// your code...
// at the end
history.push('/cart');
// you can get the history from props or can use useHistory hook
}

Why react-router fires push and pop action when replacing path?

I've a react app. In a component I have a Link comp from the react-router.
When I click on the link the router fires a push and a pop action?
Is it normal? This way I don't know how can I solve a problem.
I have a route setup like this: example/:param
and when I'm on this path how can I listen properly for the param segments change?
Code:
class Example extends Component {
fetch(param) {
// ajax stuff
}
componentWillMount() {
this.fetch(this.props.param);
}
componentWillReceiveProps(nextProps) {
this.fetch(nextProps.param);
}
render() {
// render stuff
}
}
const stateToProps = (state, ownProps) => {
return {
param: ownProps.params.param,
};
};
export default connect(stateToProps, {})(Profile);
This way componentWillReceiveProps runs twice beacuse router fires push and the pop action.
Thx for any help/advice,
Akos

Find whether a React component is being displayed or not

I want to call a promise based function before dispatching an action to the store.
The problem is that I only want to call the function when the component is going to be displayed. I use a toggle action that turns the component on and off.
Here is a sample of my code:
if ( /*component is going to be displayed*/) {
init().then(function() {
store.dispatch(toggleSomething());
});
}
else {
store.dispatch(toggleSomething());
}
Action:
export const SomethingActions = {
TOGGLE_SOMETHING: 'TOGGLE_SOMETHING'
};
export function toggleSomething() {
return {
type: SomethingActions.TOGGLE_SOMETHING
};
}
Reducer:
export default function somethingState(state = defaultState, action) {
switch (action.type) {
case somethingActions.TOGGLE_SOMETHING
return Object.assign({}, state, { open: !state.open});
default:
return state;
}
}
part of the React component:
Something.propTypes = {
display: React.PropTypes.bool.isRequired
};
function mapStateToProps(state, ownProps) {
return {
display: state.something.open
};
}
I basically want to know the value of open/display of the component above or another way to know whether the component is being displayed or not.
I don't want to pollute the render function or store a bool that changes every time I call dispatch.
Is there a way to do that?
By the sounds of it, you'd want to take advantage of React's lifecycle methods. Particularly the componentWillMount and componentWillReceiveProps.
componentWillReceiveProps does not get triggered for the initial render, so you may want to extract out the logic into a separate function so that it can be reused for both hooks:
function trigger(isDisplayed) {
if (isDisplayed) {
init().then(function() {
store.dispatch(toggleSomething());
});
}
else {
store.dispatch(toggleSomething());
}
}
componentWillMount() {
trigger(this.props.display);
}
componentWillReceiveProps(nextProps) {
trigger(nextProps.display);
}
Q1: "The problem is that I only want to call the function when the component is going to be displayed"
A1: This is definitely a problem for react lifecycle methods, in particular, componentWillMount() & componentDidMount()
Q2: "I basically want to know the value of open/display of the component above or another way to know whether the component is being displayed or not."
A2: The componentDidMount() method will be called when the component is rendered. To prevent an infinite loop where the component calls your promise on render just to call the promise again when the state changes, avoid including the toggled state in your component. Dispatch actions on component mounting that toggle the state in the store, but don't use this state in this component. This way you know whether the component is rendered without having the UI update. I hope that helps!
import React from 'react';
class StackOverFlow extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
toggleSomethingOn();
}
componentWillUnmount() {
toggleSomethingOff();
}
render() {
return (
<div>
The component has been rendered!
<br />
</div>
);
}
}
function toggleSomethingOn() {
//dispatches action to toggle state "open"
}
function toggleSomethingOff() {
//dispatches action to toggle state "closed"
}
export default StackOverFlow;
A2: If you are just looking to find out if a component has been rendered (outside of your code) you could go to your browser's developer tools and search the elements/DOM for your component html.

React/Meteor init function when data is fully rendered

I do have the following React Component, which subscribes to MongoDB loads the images from it and returns to the page.
export default class Portfolio extends TrackerReact(React.Component) {
constructor(props) {
super(props);
this.state = {
subscription: {
albumbs: Meteor.subscribe('albums')
}
}
}
componentWillUnmount() {
this.state.subscription.albums.stop();
}
albums() {
return Albums.find().fetch();
}
render() {
function init () {
$('.carousel').flickity({
// options
"lazyLoad": true
});
};
return (
<ReactCSSTransitionGroup component='div' className='carousel' transitionName='postLoad' transitionLeaveTimeout={2000} transitionEnterTimeout={2000}>
{this.albums().map( (album) => {
return <div className='carousel-cell' key={album._id}><AlbumCover albums={album} /></div>
})}
{init()}
</ReactCSSTransitionGroup>
);
}
}
The current init function makes successful init carousel classes, but it looks like the data is loaded faster then the carousel is inited and thought images are nested outside of carousel slider.
Your subscription is not yet ready and your carousel function is triggering before all data is subscribed to, that's why you are having the error.
You have to make sure you are fully subscribed to your collection. Try to create a reactive container, set up a few Session variables and subscribe properly (import container via import {createContainer} from 'meteor/react-meteor-data'):
export default createContainer(() => {
const subscription = Meteor.subscribe('albums');
subscription.ready() ? Session.set("subReady", true) : Session.set("subReady", false);
return{
album: Albums.find().fetch(),
}
}, Portfolio);
then in your render() component:
render(){
if(Session.get("subReady")){
return (
<ReactCSSTransitionGroup component='div' className='carousel' transitionName='postLoad' transitionLeaveTimeout={2000} transitionEnterTimeout={2000}>
{this.albums().map( (album) => {
return <div className='carousel-cell' key={album._id}><AlbumCover albums={album} /></div>
})}
{init()}
</ReactCSSTransitionGroup>
);
}
}
and not to forget, add the carousel code in your componentDidMount() method:
componentDidMount(){
if(Session.get("subReady")){
function init () {
$('.carousel').flickity({
// options
"lazyLoad": true
});
};
}
}
I didn't test this code on my computer, but hopefully it works out for you.
If you want to use your method of subscribing, then make sure that:
1) The subscription is ready.
2) Make sure your carousel code is in your componentDidMount() method and is wrapped in a reactive way to trigger when the data is actually ready/subscribed to.

React unmount component on window unload

I am rendering to the DOM with ReactDOM. I would like to know whether I have to manually unmount React components on window unload events. If so, what is the best practice here? What I can think of is the following:
class MyComponent extends React.Component {
constructure(props) {
super(props);
this.handleUnload = this.handleUnload.bind(this);
}
handleUnload() {
ReactDOM.unmountComponentAtNode(this.getDomNode());
}
componentWillMount() {
window.addEventListener('beforeunload', this.handleUnload);
}
componentWillUnmount() {
window.removeEventListener('beforeunload', this.handleUnload);
}
...
}
Please advice, and thanks.

Categories