I am trying to show blinking text using react:
class BlinkLable extends React.Component {
constructor(props) {
super(props);
this.state = {showlabel: true,
label: this.props.label
};
this.myFunction = this.myFunction.bind(this);
}
myFunction()
{
var sLb = ! (this.state.showlabel);
this.setState({showlabel: sLb});
}
componentDidMount() {
setTimeout(this.myFunction, 3000)
}
render() {
return (
<div>
{(this.state.showlabel)?this.state.label:''}
</div>
);
}
}
ReactDOM.render(
<BlinkLable label='MY MESSAGE'/>,
document.getElementById('labelId')
);
However, after it shows MY MESSAGE, this message dissapears and never comes back. What could be the problem?
You need to use setInterval() method.
componentDidMount() {
setInterval(this.myFunction, 3000)
}
More Info: 'setInterval' vs 'setTimeout'
Modify this function to:
myFunction()
{
this.setState((prevState) => {
return {
showlabel: !prevState.showLabel
}
});
}
class BlinkLable extends React.Component {
constructor(props) {
super(props);
this.state = {showlabel: true,
label: this.props.label
};
this.myFunction = this.myFunction.bind(this);
}
myFunction(){
var sLb = ! (this.state.showlabel);
this.setState({showlabel: sLb});
}
render(){
return (
<div>
{(this.state.showlabel)?this.state.label:''}
</div>
);
}
componentDidUpdate() {
setTimeout(this.myFunction, 2000)
}
componentDidMount(){
setTimeout(this.myFunction, 2000)
}
}
ReactDOM.render(
<BlinkLable label='MY MESSAGE'/>,
document.getElementById('labelId')
);
<div id="labelId"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
you need to know react's component life cycle.
componentDidMount() is called only when a component is mounted.
componentDidMount() is invoked immediately after a component is
mounted. Initialization that requires DOM nodes should go here.
Therefore if you want to keep blinking, add componentDidUpdate().
Related
I am quite new in React... I have page where window is showing with little delay..
it is made with Hooks:
export default function LoginPage() {
const [cardAnimaton, setCardAnimation] = React.useState('cardHidden');
setTimeout(function() {
setCardAnimation('');
}, 700);
<form>
<Card login className={classes[cardAnimaton]}>
Now I want to use classes in that page and I want to preserve the same effect..
So I am trying something like:
export default class LoginPage extends React.Component {
constructor(props) {
super(props);
this.state = {
cardHidden: true,
};
}
componentDidMount() {
this.timeout = setTimeout(() => {
this.setCardAnimation('');
}, 700);
}
setCardAnimation = () => {
this.cardAnimaton({ cardHidden: false });
};
I have no idea... got stuck there...
You just need to set your cardHidden: false inside componentDidMount and then you can add animation based on cardHidden state.
here is a working Demo which I used cardHidden state to show or hide different text on screen which you can use this method for adding different animation.
just click Run code snippet to see how it works
class LoginPage extends React.Component {
constructor(props) {
super(props);
this.state = {
cardHidden: true,
};
}
componentDidMount() {
this.timeout = setTimeout(() => {
this.setState({
cardHidden: false
});
}, 700);
}
render() {
if(this.state.cardHidden){
return <div>I'm Hidden</div>
} else {
return <div>Haha, I'm Visible</div>
}
}
}
const rootDiv = document.getElementById('root');
ReactDOM.render(<LoginPage />, rootDiv);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
In class-based component, you need to use this.setState to update the state.
export default class LoginPage extends React.Component {
constructor(props) {
super(props);
this.state = {
cardHidden: true,
};
}
componentDidMount() {
this.timeout = setTimeout(() => {
this.setState({ cardHidden: false });
}, 700);
}
...
check https://reactjs.org/docs/react-component.html#setstate
I think this is a rather simple question, but I am trying to self-learn React.js and am a bit confused about how audio loops. I understand looping when rendering and returning plain html audio tags, but I am not sure how to do it without. So far I have learned how to toggle play and pause buttons thanks to another StackOverflow question I found, but am not sure how to make the audio loop as well. I would like to keep the current code if possible (I tried to use the audio tags mentioned above instead when rendering, but it was hard to re-incorporate the image toggling again) and just learn how to incorporate looping into it. Any help or resources would be much appreciated! Below is the code I have reduced it to so far:
export class PlaySound extends Component {
constructor(props) {
super(props);
this.state = {
play: true
};
this.url = "https://actions.google.com/sounds/v1/water/waves_crashing_on_rock_beach.ogg";
this.audio = new Audio(this.url);
this.togglePlay = this.togglePlay.bind(this);
}
togglePlay() {
this.setState({
play: !this.state.play
});
this.state.play ? this.audio.play() : this.audio.pause();
}
render() {
return (
<div>
<button
id="audioBtn"
onClick={this.togglePlay}> {this.state.play ? <PlayArrow /> : <Pause />}
</button>
</div>
);
}
}
you can just set loop = true
togglePlay() {
this.setState({
play: !this.state.play
});
this.state.play ? this.audio.play() : this.audio.pause();
this.audio.loop = true;
}
You can add an ended listener to your Audio object in which you set the time back to 0 and start playing it again.
class PlaySound extends Component {
constructor(props) {
super(props);
this.state = {
play: true
};
this.url = "https://actions.google.com/sounds/v1/water/waves_crashing_on_rock_beach.ogg";
this.audio = new Audio(this.url);
this.audio.addEventListener('ended', function () {
this.currentTime = 0;
this.play();
}, false);
this.togglePlay = this.togglePlay.bind(this);
}
// ...
}
class PlaySound extends React.Component {
constructor(props) {
super(props);
this.state = {
play: false
};
this.url = "https://actions.google.com/sounds/v1/water/air_woosh_underwater.ogg";
this.audio = new Audio(this.url);
this.audio.addEventListener('ended', function () {
this.currentTime = 0;
this.play();
}, false);
this.togglePlay = this.togglePlay.bind(this);
}
togglePlay() {
const wasPlaying = this.state.play;
this.setState({
play: !wasPlaying
});
if (wasPlaying) {
this.audio.pause();
} else {
this.audio.play()
}
}
render() {
return (
<div>
<button
id="audioBtn"
onClick={this.togglePlay}> {this.state.play ? "Pause" : "Play"}
</button>
</div>
);
}
}
ReactDOM.render(<PlaySound />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I have a react component(parent) that has as state another react component(child)
The parent passes down is't state as props to the child.
But if I do setState on the passed down property, it does not update in the child.How do I make such that a change in state is reflected in the child?
See code:
class Child extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
{this.props.x}
</div>
)
}
}
class Parent extends React.Component {
constructor(props) {
super(props)
this.state = {x: 1, intervalID: 0, currentScreen: <Child x={0} />}
}
componentDidMount() {
let self = this
let intervalID = setInterval(function() {
self.setState({x: self.state.x+1})
}, 1000)
self.setState({intervalID: intervalID, currentScreen: <Child x={self.state.x} />})
}
render() {
return (
<div>
{this.state.currentScreen}
</div>
)
}
}
ReactDOM.render(<Parent />, document.getElementById('app'))
Below code is working.
import React from 'react';
import ReactDOM from 'react-dom';
class Child extends React.Component {
render() {
return (
<div>
{this.props.x}
</div>
)
}
}
class Parent extends React.Component {
constructor(props) {
super(props)
this.state = {x: 1, intervalID: 0, currentScreen: <Child x={0} />}
}
componentDidMount() {
let intervalID = setInterval(() => {
const x = this.state.x + 1;
this.setState({
x: x,
currentScreen: <Child x={x} />
});
}, 1000)
this.setState({intervalID: intervalID, currentScreen: <Child x={this.state.x} />})
}
render() {
return (
<div>
{this.state.currentScreen}
</div>
)
}
}
ReactDOM.render(<Parent />, document.getElementById('root'))
Your child component is not updating because for the lifecycle of parent component componentDidMount is only called once when it is being mounted.
If you need to update your state on regular interval you can do something like :
import React, { Component } from 'react';
import { render } from 'react-dom';
class Child extends Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
{this.props.x}
</div>
)
}
}
class Parent extends Component {
constructor(props) {
super(props)
this.state = { x: 1, intervalID: 0 }
}
componentDidMount() {
let self = this
let intervalID = setInterval(function () {
self.setState({ x: self.state.x + 1 })
}, 1000)
self.setState({ intervalID: intervalID })
}
render() {
return (
<div>
<Child x={this.state.x}/>
</div>
)
}
}
render(<Parent />, document.getElementById('root'))
for your case, just so when setState is done, it will call render again and it will pass the latest value of x to the child component.
You can check out live working example on stackblitz
It is a bad practise to maintain JSX in the state. Move all your JSX into the render() and use state variables to manage the state as shown below (For brevity only the Parent component code is shown).
Further instead of doing let self=this use the arrow function for clarity.
Note that you need to use the updater function when setting the state if your new state depends on the previous state. This is because React does batch updates for state. More information can be found in the official documentation.
class Parent extends React.Component {
constructor(props) {
super(props)
this.state = { x: 1 }
}
componentDidMount() {
setInterval(() => {
this.setState((prevState, props) => {
return { x: prevState.x + 1 };
});
},3000)
}
render() {
return (
<div>
<Child x={this.state.x} />
</div>
)
}
}
ReactDOM.render(<Parent />, document.getElementById('root'))
Above function will update the value of x every 3 seconds. Below is a working example
https://codesandbox.io/s/2677zoo4p
I'm trying to run the below code in React+Redux but am running into an unhandled
exception 'NodeInvocationException: Cannot read property 'showText' of
null TypeError: Cannot read property 'showText' of null'
import * as React from 'react';
import { NavMenu } from './NavMenu';
import { Component } from 'react';
export interface BlinkState
{
showText: boolean;
text: '';
}
type BlinkProps = BlinkState;
class Blink extends React.Component<BlinkProps, BlinkState> {
constructor(props: BlinkProps) {
super(props);
//this.state = { showText: true };
this.setState({ showText: true, text: props.text });
// Toggle the state every second
setInterval(() => {
this.setState(previousState => {
return { showText: !previousState.showText };
});
}, 1000);
}
render() {
let display = this.state.showText ? this.props.text : ' ';
return <div>{ display }</div>;
}
}
export class Layout extends React.Component<{}, {}> {
public render() {
return <div className='container-fluid'>
<Blink showText=false text='I love to blink' />
</div>;
}
}
I'm just trying to figure out how to render the Blink copmonent with the props passed in...
You missed the basic thing, use of constructor and setState, use of constructor is to initialize the state value and use of setState is to update the state value, so using setState inside `constructor doesn't makes any sense.
Better way will be, initialise the state in constructor and to run the time use componentDidMount lifecycle method, also don't forgot to stop the time before unmounting the component, to clear it use componentWillUnmount lifecycle method.
Write the component like this:
class Blink extends React.Component<BlinkProps, BlinkState> {
constructor(props: BlinkProps) {
super(props);
this.state = { showText: false };
}
componentDidMount(){
this.timer = setInterval(() => {
this.setState(previousState => {
return { showText: !previousState.showText };
});
}, 1000);
}
componentWillUnmount(){
clearInterval(this.timer)
}
render() {
let display = this.state.showText ? this.props.text : ' ';
return <div>{ display }</div>;
}
}
Working code:
class Blink extends React.Component {
constructor(props) {
super(props);
this.state = { showText: true, text: props.text };
}
componentDidMount(){
this.timer = setInterval(() => {
this.setState(prev => {
return { showText: !prev.showText };
});
}, 1000);
}
componentWillUnmount(){
clearTimer(this.timer)
}
render() {
let display = this.state.showText ? this.props.text : ' ';
return <div>Hello { display }</div>;
}
}
class Layout extends React.Component{
render() {
return <div className='container-fluid'>
<Blink text='I love to blink' />
</div>;
}
}
ReactDOM.render(<Layout/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'/>
You should not specify actions to be taken in the constructor or use setState there, constructor should be used to simply set an initial state.
Also you might need to update the state text since its being set based on props. Do it in the componentWillReceiveProps.
Also when you are using setInterval, make sure to clearInterval when the componentUnmounts
constructor(props: BlinkProps) {
super(props);
this.state = { showText: true, text: props.text };
}
componentWillReceiveProps(nextProps) {
this.setState({text: nextProps.text});
}
componentDidMount() {
// Toggle the state every second
this.interval = setInterval(() => {
this.setState(previousState => {
return { showText: !previousState.showText };
});
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval)
}
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'));