I'm new on react and now I have a problem. I have in my app 3 component:
App Component:
class App extends Component {
constructor(){
super();
this.state = {
showToast:false,
toastMessage: ""
};
this.handleShowToast = this.handleShowToast.bind(this);
};
handleShowToast(message) {
this.setState({ showToast: true, toastMessage: message});
setTimeout(function() {
if(this.state.showToast){
this.setState({ showToast: false });
}}.bind(this), 2000);
};
render() {
return (
<div id="cont">
<Toast showToast={this.state.showToast} messageToast={this.state.toastMessage} />
<Header handleToast={this.handleShowToast}/>
</div>
);
}
}
In my Header components I click on button and hadleShowToast is execute and Toast Component is correctly show and it work, but I would (now i make with setInterval, but doesn't work, because if I click a second time button it immediately hide because there is a precendent setInterval) hide Toast component, after 2 second, if I don't click again a button, but if I click again button in Header component i would reset timer.
How Can I do this?
You can use clearTimeout to clear timers:
handleShowToast(message) {
this.setState({ showToast: true, toastMessage: message});
if (this.timer) {
clearTimeout(this.timer)
}
this.timer = setTimeout(function() {
if(this.state.showToast){
this.setState({ showToast: false });
}
this.timer = null;
}.bind(this), 2000);
}
Related
How to force re render a component in react ? I think this.forceUpdate(); re render Viewer Component, but it s not working.
In fact, I need to reload the page if I want to get the localStorage urn for docUrn.
class Test extends React.Component {
constructor(props) {
super(props);
this.setState({value: localStorage.getItem('urn')});
this.state = {
urn: localStorage.getItem('urn') || null,
};
}
// check every 2s if urn is updated
componentDidMount() {
setInterval(() => {
if (this.state.urn !== localStorage.getItem('urn')) {
this.setState({urn: localStorage.getItem('urn')});
if (this.state.urn === "urn:null") {
notify('Please select another model', 'error', 1000);
} else {
notify('Model changed', 'success', 1000);
//this.forceUpdate() not working
//window.location.reload()
this.forceUpdate();
}
}
}, 2000);
}
render() {
return (
<Viewer
getToken={renewExpiredToken}
//re render viewer with new urn for docUrn
docUrn={
this.state.urn
}
/>
);
}
}
I'm trying to implement a suggestion list. I use <input/> followed by a number of <div>s. When the input element is focused, list, or divs, will show; when the input element is not focused, or blurred, the divs are unmounted. I want to print the content in div before the boolean variable isFocused is set to false. But now if I blur the input and click div, the printContent will not be triggered because isFocused has been set to false. Now I am using setTimeout to deal with this problem. Is there a better way to resolve this? Here is the code snippet:
CodeSandbox
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isFocused: false
}
}
handleFocus = () => {
this.setState({ isFocused: true });
}
handleBlur = () => {
setTimeout(() => this.setState({ isFocused: false }), 1000);
}
printContent = () => {
console.log('print content');
}
render() {
console.log(this.state.isFocused)
return(
<div>
<input onFocus={this.handleFocus} onBlur={this.handleBlur} />
{
this.state.isFocused ?
<div key='1' onClick={this.printContent}>content1</div> :
null
}
</div>
);
}
}
What is the difference between
class App extends Component {
open = false
render () {
<Button onPress=(() => { this.open = false}) />
}
}
class App extends Component {
constructor() {
this.state({
open: false
})
}
render () {
<Button onPress=(() => { this.setState({ open: true })}) />
}
}
For me, it works the same, and I used this without a state and never had issues.
this.open is referring to the property of class App while this.state, if you are using React, it is referring to your components local state.
this.setState({ open: true }) will update the state and also rerenders your components while this.open = false will not trigger any rerenders
This is because you are not using open inside your render method. Changing state re-renders the component with different data, while class properties doesn't.
To better understand the difference, you could try clicking the button in these two classes:
class App extends Component {
open = false
render () {
let isOpen = "Not open"
if (this.open) {
isOpen = "Open!"
}
return (<View><Button onPress=(() => { this.open = false}) /><Text>{isOpen}</Text></View>)
}
}
class App extends Component {
constructor() {
this.state({
open: false
})
}
render () {
let isOpen = "Not open"
if (this.state.open) {
isOpen = "Open!"
}
return (<View><Button onPress=(() => { this.setState({ open: true })}) /><Text>{isOpen}</Text></View>)
}
}
I made a button that changes its label from 'extract' to 'extracted' when clicked then it becomes disabled. What I want to do now is for it to have a loading indicator when clicked and stop when the button is disabled.
I tried
document.getElementById(inputID).setAttribute("loading", "true");
when button is clicked but found out that it doesn't work on buttons. I am also trying right now to use setState with my
document.getElementById("btnTesting").innerHTML = "EXTRACTED";
class DashboardPage extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
}
onClickBtn = () => {
this.setState({ loading: true});
document.getElementById("btnTesting").innerHTML = "EXTRACTED";
document.getElementById("btnTesting").setAttribute("disabled","true");
}
render() {
return (
<Button id="btnTesting" onClick={this.onClickBtn} loading={this.state.loading}>EXTRACT</Button>
)
}
}
I expect to have a loading indicator when clicked then stop when button is disabled. But the screen turns blank. I look in the console and saw this error
Uncaught DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.
The above error occurred in the component:
blah .
blah .
Uncaught DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.
Because you're using React, you don't need to use the innerHTML or setAttribute to change button text or disabled state.
You can use state varibles buttonText, initialised to "Extract" and isDisabled, initialised to false, and you can change the state after the button is done executing.
class DashboardPage extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
buttonText: "EXTRACT",
isDisabled: false
};
}
onClickBtn = () => {
this.setState({ loading: true });
setTimeout(() => {
this.setState({
buttonText: "EXTRACTED",
isDisabled: true,
loading: false
});
}, 2000);
};
render() {
return (
<Button
id="btnTesting"
onClick={this.onClickBtn}
loading={this.state.loading}
disabled={this.state.isDisabled}
>
{this.state.buttonText}
</Button>
);
}
}
I've added a setTimeout of 2000ms so you can see the loading indicator.
Find the demo here: https://codesandbox.io/s/antd-reproduction-template-l1d4r
Can you check if below code solves your issue ? I Added timer to demonstrate time affect so that loading becomes evident.
With ReactJS, you don't have to use setAttribute or innerHTML as ReactJS uses virtualDOM. Even if you use them, It can get DOM in inconsistent state. As per standard React practice you should handle your requirements (i.e changing DOM) with state variables
class DashboardPage extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: {"btn1": false},
disabled: false,
buttonText: 'Extract'
}
onClickBtn = (btnStr) => {
let loadingCopy = Object.assign({},this.state.loading)
loadingCopy[btnStr] = true
this.setState({loading: loadingCopy})
setInterval(() => {
loadingCopy[btnStr] = false
this.setState({ loading: loadingCopy, buttonText: 'Extracted', disabled: true });
}, 3000);
}
render() {
return (
<ButtononClick={() =>this.onClickBtn("btn1")} loading={this.state.loading["btn1"]} disabled={this.state.disabled}>{this.state.buttonText}</Button>
)
}
}
import { Button } from 'antd';
import React from "react";
class SubmitButton extends React.Component {
state = {
loadings: [],
};
enterLoading = index => {
this.setState(({loadings}) => {
const newLoadings = [...loadings];
newLoadings[index] = true;
return {
loadings: newLoadings,
};
});
};
render() {
const {loadings} = this.state;
return (
<>
<Button type="primary" htmlType="submit" loading={loadings[0]} onClick={() => this.enterLoading(0)}>
Submit
</Button>
</>
);
}
Code:
https://codesandbox.io/s/withered-framework-w5lmc?file=/src/App.js
I just want to know, what is the best way to show loading state before data that is being fetched by AJAX loaded. I've tried to reproduce it using setInterval on codepen. Code
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isFetching: true,
};
}
componentWillMount() {
let that = this;
setTimeout(function() {
that.setState({
isFetching: false,
});
}, 2000);
}
render() {
return (
<div>
{this.state.isFetching ? 'Fetching' : 'Done'}
</div>
);
}
}
React.render( <App / > , document.getElementById('root'));