How to remove loader when entering escape in react? - html

I need to come out from page after entering escape button , when the page takes much time for loading. I need to exit that loading when it takes longer time
For loading I am using
dispatcher.dispatch({
type:'Loader',
showLoader: true
})

You will have to add an event listener i.e. keyup or keydown. When any key is pressed, just compare its keyCode with escape button's keycode i.e. 27.
In react, event listener should be added in componentDidMount and removed in componentWillUnmount.
Here is an example. You can modify logic according to your requirements.
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
loading: true,
}
this.onKeyUp = this.onKeyUp.bind(this)
}
componentDidMount() {
document.body.addEventListener('keyup', this.onKeyUp)
}
componentWillUnmount() {
document.body.removeEventListener('keyup', this.onKeyUp)
}
onKeyUp(e) {
if (/27/.test(e.keyCode)) {
this.setState({ loading: false })
}
}
render() {
if (this.state.loading) {
return <div>Loading</div>
}
return <div>Loaded</div>
}
}
Hope it helps.

Related

Check current component after timeout

I'm in a component called "recoger_success" and I want it to navigate to the home component after 10 seconds after clicking a button that has countdown() linked to it. The problem is that if I navigate to another component before the timeout gets to 0 then after the 10 seconds it doesn't matter in which component I am, it will always go to home component. I don't want this I want it only to go to the home component if the user is still on the timeout component otherwise ignore it..
I have tryed this to know the url of the actual component but it doesn't work..
countdown(){
setTimeout(() => {
if (this.route.snapshot.url.toString() == 'recoger_success'){
this.router.navigate([""]);
}
}, 10000);
}
apreciate any help.
Assign timeout to a variable and at the time you manually exist the page, clear the timeout
countdown(){
this.timeout = setTimeout(() => {
if (this.route.snapshot.url.toString() == 'recoger_success'){
this.router.navigate([""]);
}
}, 10000);
}
function myStopFunction() {
clearTimeout(this.timeout);
}
You need to bind the setTimeout to a variable.
component.ts
import { Component, OnDestroy } from '#angular/core';
export class Component implements OnDestroy {
countdownTimer: any;
countdown() {
if (this.countdownTimer) {
clearInterval(this.countdownTimer);
}
this.countdownTimer = setTimeout(() => {
if (this.route.snapshot.url.toString() == 'recoger_success') {
this.router.navigate([""]);
}
}, 10000);
}
ngOnDestroy() {
if (this.countdownTimer) {
clearInterval(this.countdownTimer);
}
}
}

Simulating a click on a React Element

I'm using React with Leaflet, and want to launch the drawing menu immediately upon the component mounting, without making the user click any buttons. The React Leaflet Draw API is a bit opaque on this, and what I'd like to do to make this simple is to trigger a click on the appropriate button programmatically, without the user having to. I'll then hide the button.
The trouble is that I'm not having any luck either using the .click() or the MouseEvent('click') APIs. Here's my attempt at the latter:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../../../actions';
import { Polygon, FeatureGroup } from 'react-leaflet';
import { EditControl } from 'react-leaflet-draw';
export class DrawNewPlot extends Component {
componentDidMount() {
let simulateClick = elem => {
let evt = new MouseEvent('click', {
bubbles: true,
view: window
});
};
let drawControl = document.getElementsByClassName('leaflet-draw-toolbar');
simulateClick(drawControl);
}
render() {
return (
<FeatureGroup>
<EditControl
position="bottomright"
onEdited={e => {
e.layers.eachLayer(a => {
this.props.setNewPlotGeojson(a.toGeoJSON());
});
}}
onCreated={e => {
this.props.setNewPlotGeojson(e.layer.toGeoJSON());
}}
draw={{
marker: false,
circle: false,
rectangle: false,
polygon: true,
polyline: false,
circlemarker: false,
edit: false
}}
edit={{ edit: false }}
/>
</FeatureGroup>
);
}
}
function mapStateToProps(state) {
return {
addingNewPlotDetails: state.plots.addingNewPlotDetails
};
}
export default connect(mapStateToProps, actions)(DrawNewPlot);
Any thoughts as to what I'm doing wrong?
Your simulateClick method creates the event, but never dispatches it. Try adding elem.dispatchEvent(evt);
Although I must add that simulating mouse click this way just to trigger some initial side effect feels wrong. I am not familiar with Leaflet, but it could be worth checking if they have some API to set initial state

ReactJS component textarea not updating on state change

I'm trying to write a note taking/organizing app and I've run into a frustrating bug.
Here's my component:
import React from 'react';
const Note = (props) => {
let textarea, noteForm;
if (props.note) {
return (
<div>
<button onClick={() => {
props.handleUpdateClick(props.selectedFolderId, props.selectedNoteId, textarea.value);
}}>
Update
</button>
<textarea
defaultValue={props.note.body}
ref={node => {textarea = node;}}
/>
</div>
);
} else {
return <div></div>;
}
};
export default Note;
As it currently stands, whenever I switch between notes and rerender the note component with new content from the note.body prop, the textarea does not change and retains the content from the previous note. I've tried using the value attribute instead of the defaultValue attribute for the text area which doe fix the problem of the text area content not changing when the component rerenders, but when I do that I'm longer able to type in the textarea field to update the note
Doe anyone know a way I can both allow for users to type in the text field to update the note as well as have the textarea content change when I render different notes?
Thank you
The problem is that setting the value to your prop will cause all re-renders of the component to use the same prop, so new text is obliterated. One solution is to preserve the text in the local state of the component. To simultaneously listen to prop changes, you can set the state when you receive new props.
const Note = React.createClass({
getInitialState() {
return {
text : this.props.note.body
}
},
componentWillReceiveProps: function(nextProps) {
if (typeof nextProps.note != 'undefined') {
this.setState({text: nextProps.note.body });
}
},
render() {
if (this.props.note) {
return (
<div>
<button onClick={(e) => {
// Fire a callback that re-renders the parent.
// render(this.textarea.value);
}}>
Update
</button>
<textarea
onChange={e => this.setState({ text : e.target.value })}
value={this.state.text}
ref={node => {this.textarea = node;}}
/>
</div>
);
} else {
return <div></div>;
}
}
});
https://jsfiddle.net/69z2wepo/96238/
If you are using redux, you could also fire an action on the change event of the input to trigger a re-render. You could preserve the input value in a reducer.
Because componentWillReceiveProps is now unsafe Max Sindwani's answer is now a little out date.
Try these steps:
convert your component to a class
now you can include the shouldComponentUpdate() lifecycle hook
create your event handler and pass it into onChange
in <textarea> you can swap out defaultValue attribute for value (just use event.preventDefault() in the handler so that a user can continue to update text if required)
import React from 'react';
export class Note extends React.Component {
constructor(props) {
super(props);
this.state={text: this.props.note.body}
}
shouldComponentUpdate(nextProps) {
if(nextProps.note.body !== this.state.text) {
this.setState({text: nextProps.note.body})
return true;
}
return false;
}
updateText = (event) => {
event.preventDefault();
this.setState({text: nextProps.note.body});
}
render() {
if (this.props.note) {
return (
<div>
<textarea
onChange={this.updateText}
value={this.state.text}
name={'display'}
/>
</div>
);
} else {
return <div></div>;
}
}});

react-router root onChange to replace path infinite

It seems if I change path in root onEnter or onChange hook, the url will change infinite. But if I change path in child routes, it will work. Actually I want to handle the authentication in one place, otherwise every child route should handle the same logic.
{
path: '/',
onChange: function(prevState, nextState, replace, callback) {
if(!logined) {
replace('login');
}
},
childRoutes: [
....
]
}
It changes infinitly because onChange invokes on replace
try
onChange: function(prevState, {location:{pathname:next}}, replace)=> {
if(!logined && next !== '/login') {
replace('/login');
}
}
also to handle the authentication in one place, you can use HOC, something like that
const CheckAuth = (isLogined, redirectPath) => Component =>
class CheckAuth extends React.Component {
componentWillUpdate(nextProps, nextState){
//Check auth on change
this.checkAuth(nextProps);
}
componentWillMount(){
//Check auth on enter
this.checkAuth(this.props);
}
checkAuth({location}){
if(!isLogined && location.pathname!==redirectPath) {
browserHistory.replace(redirectPath);
}
}
render(){
return (<Component {...this.props}/>);
}
};
and App component
class App extends React.Component { ... }
export default CheckAuth(isLogined,'/login')(App);
also, there is a way with redux-auth-wrapper

Invoke function from React component declared as variable

How to invoke React component's function when this component is given in variable? I have a Parent that passes Test class into Child component, and this child wants to change something in Test.
export class Parent extends React.Component {
render() {
let test = (<Test />);
return (<Child tester={test} />);
}
}
export class Child extends React.Component {
render() {
this.props.tester.setText("qwerty"); // how to invoke setText, setState or something like that?
return ({this.props.tester});
}
}
export class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
text: this.props.text || ""
};
}
setText(text) {
this.setState({ text: text });
}
render() {
return (<div>{this.state.text}</div>);
}
}
I think you should think about life cycle of react components.
Please try the code below(I just added logging), and observe logs carefully.
export class Parent extends React.Component {
render() {
let test = (<Test />);
return (<Child tester={test} />);
}
}
export class Child extends React.Component {
render() {
console.log("Child render"); // <= logging added!
// this.props.tester.setText("qwerty");
// What kind of object is 'this.props.tester(= <Test />)' here???
return ({this.props.tester});
}
}
export class Test extends React.Component {
constructor(props) {
super(props);
console.log("Test constructor"); // <= logging added!
this.state = {
text: this.props.text || ""
};
}
setText(text) {
// this.setState({ text: text });
// this is another problem. We cannot call setState before mounted.
this.state.text= text;
}
render() {
return (<div>{this.state.text}</div>);
}
}
If so, you will see 2 important facts.
'Test' component is not instantiated yet, when you call 'setText'.
How can we call a method of object which is not instantiated? Cannot!
this means 'this.props.tester' is not an instance of 'Test' component.
But if you really want to exec your code, modify Child.render like this.
render() {
var test = new Test({props:{}});
// or even this can work, but I don't know this is right thing
// var test = new this.props.tester.type({props:{}});
test.setText("qwerty");
return test.render();
}
But I don't think this is a good way.
From another point of view, one may come up with an idea like,
render() {
// Here, this.props.tester == <Test />
this.props.tester.props.text = "qwerty";
return (this.props.tester);
}
but of course it's not possible, because 'this.props.tester' is read-only property for Child.