ReactJS change background image dynamically doesn't work - javascript

I am new to reactJS. I want to create a component to change background images dynamically. I just write a javascript to update background image every 5 seconds but it doesn't work. These images are local images, I want to loop them and display them. Would you please take a look? Thank you very much!
import * as React from 'react';
import * as image from './resources';
const TIME_TICK_PERIOD = 5000;
var images =['resources/yellowstone.jpg','resources/yellowstone2.jpg','resources/yellowstone3.jpg'];
export class BackgroundImage extends React.Component {
constructor(props) {
super(props);
this.state = {
index:0
};
}
componentDidMount() {
this.timerID = setInterval(() => this.tick(), TIME_TICK_PERIOD);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
let idx = this.state.index;
if(idx >=images.length-1) {
this.setState({
index: 0
});
} else {
this.setState({
index: idx+1
})
}
}
render() {
return (
<div className="hints-on-home-screen">
<div
style={{
position: absolute,
backgroundImage: `url(${images[this.state.index]}`)
}}
/>
</div>
);
}
}

You are saving your initial index of 0 outside the component scope. So index + 1 is always evaluating to 1. Instead of saving the imagePath in your state, save the index in your state. Then increment it in tick. Then reference images[index].

Related

How to change text on mouse event in React

I'm trying to use the onMouseDown event in react to change the text but it doesn't work.
I saw a similar code which actually worked so I have no idea what could be wrong.
import React, { Component } from "react";
import "./ContentComponent.css";
class Content extends Component{
constructor(){
super()
this.onClickForward = this.onClickForward.bind(this)
this.onClickBack = this.onClickBack.bind(this)
const img0 = require('./images/dog1.jpg');
const img1 = require('./images/dog2.jpg');
const img2 = require('./images/dog3.jpg');
const img3 = require('./images/dog4.jpg');
this.state={
index: 0,
imgList: [img0, img1, img2, img3]
}
this.state2 = {
tekst: "Pies"
}
}
onClickForward(){
if (this.state.index + 1 === this.state.imgList.lenght) {
this.setState({
index: 0
})
} else{
this.setState({
index: this.state.index +1
})
}
}
onClickBack(){
if (this.state.index - 1 === -1) {
this.setState({
index: this.state.imgList.lenght -1
})
} else{
this.setState({
index: this.state.index - 1
})
}
}
zmianaTekstu() {
this.setState2({
tekst: "Pies domowy - udomowiony gatunek ssaka drapieżnego z rodziny psowatych, traktowany przez niektóre ujęcia systematyczne za podgatunek wilka."
})
}
render(){
return(
<div className="info">
<img src={this.state.imgList[this.state.index]} alt="" className="mainImage" />
<div className="btns">
<button onClick={this.onClickBack}>Poprzednie</button>
<button onClick={this.onClickForward}>Następne</button>
</div>
<div className="textInfo">
<h3 onMouseDown={() => this.zmianaTekstu()}>Click to change text</h3>
<p>{this.state2.tekst}</p>
</div>
</div>
)
}
}
export default Content;
Console says
Uncaught TypeError: this.setState2 is not a function
The first state which changes images on button click actually works but I've pasted the whole code since maybe there is some interaction.
You should use only one react's state in Class Component, in that way can access the setState and Update it. A state is an object so it can contain inside of it more variables, arrays, or even more objects. just hold inside the same state, variable for tekst
and update it like you update the first state, like so:
this.state = {
index: 0,
imgList: [img0, img1, img2, img3],
tekst: 'pies',
}
And then update the state whenever you need, like so:
this.setState({
tekst: "Pies domowy - udomowiony gatunek ssaka drapieżnego z rodziny psowatych, traktowany przez niektóre ujęcia systematyczne za podgatunek wilka."
})
the setState method is specific to your component, you cannot use another method to modify another state in your component, you could put all your data in the first state object or also use state hooks ?

React refresh component when variable has changed

I am calling a React component BarChart with two props, a name and a value. As you can see in the below code, the variable value is set to a new random number every second:
let random1;
function setRandom() {
random1 = Math.floor(Math.random() * 10) + 1;
}
setRandom();
setInterval(setRandom, 1000);
return (
<div className="Content">
<BarChart name1={"A"} value1={random1}/>
</div>
)
}
Inside the React component I call it by using this.props.value1. When I do a console.log(this.props.value1) each second inside the React component, I get an error that the variable is undefined after the first print is made. So, it prints to the console 1 time and then it just prints an error for all of the rest attempts.
This is how I print the variable inside the component:
setRandom() {
console.log(this.props.value1)
}
componentDidMount() {
this.setRandom();
setInterval(this.setRandom, 1000);
}
What I really want to do is that whenever a new random value is generated outside the component, the component should see that the variable has changed and refresh the component and use the new prop.
Could you please advise me?
The standard way to do this is to make random1 a piece of state information, and then use this.setState to update it.
The first link above has an example of a ticking clock, which is virtually identical to your example of a random number every second. Here's that example, which you can readily adapt to your task:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
constructor(props) {
super(props);
//innitialize the random number in the state
this.state = {random: Math.floor(Math.random() * 10) + 1};
}
//generate the random number and keep in on the state
setRandom() {
this.setState({random: Math.floor(Math.random() * 10) + 1})
}
//clear the timer when component unmount
componentWillUnmount() {
clearInterval(this.timer);
}
componentDidMount() {
//start the timer when component mount
this.timer = setInterval(()=>this.setRandom(), 1000);
}
//pass the random value from state as props to the component BarChart
return (
<div className="Content">
<BarChart name1={"A"} value1={this.state.random}/>
</div>
)
}

React JSX Dynamic Content : increment in top property

i am absolutely begginner in react so please forgive me , i am stuck with Dynamic content creation , i cant make increment in top property , after render where i am using map and i am using top property , i dont know how to increase the num , i have tried in setstate but it does not work each time , it happens before render , and i only see pics at the last location
class People extends React.Component {
componentDidMount = () => {
//$('#Dynamic').hide()
}
constructor(props){
super(props);
this.state = {
Info : []
}
var Ref = firebase.database().ref('Users');
Ref.once('value' , (i) => {
i.forEach((y)=>{
var data = y.val()
myArray[c] = data.Photo;
// alert(myArray[c]) ;
c++ ;
this.setState({
Info : myArray
})
})
})
}
render () {
n += 100;
return (
<div>
<div id = 'Dynamic' >
<div id = 'hi'> { this.state.Info.map(i =>
{ return <img style = {{'top' : n }} className = 'public' src = {i} /> }
)}
</div>
</div>
</div>
);
}
}
export default People
setState() does not immediately mutate this.state but creates a pending state transition. So, no multiple rendering while calling setState in a loop.

React: How can I call a method only once in the lifecycle of a component, as soon as data.loading is false

I have a React component with a prop 'total' that changes every time the component is updated:
function MyView(props) {
const total = props.data.loading ? 0 : props.data.total;
return (
<p> total </p>
);
}
The first time the component mounts the total is say 10. Every time the component is updated because of a prop change the total goes up.
Is there a way I can display the original total (in this example 10)?
I have tried setting it in this.total inside componentDidMount, but props.data.total is not yet available when componentDidMount is called. Same with the constructor. The total only becomes available when props.data.loading is false.
In order to get access to lifecycle features, you must move from function, stateless component, to a class component.
in the below example, InitialTotal is initialized in the construstor lifecycle method and it never changes.
currentTotal, is incremented each time the render function is called - when the component is re-rendered (because of props change or state changes)
it should look something like that:
class MyView extends React.Component {
constructor(props) {
super(props)
this.initialTotal = 10;
this.currentTotal = 10;
}
render() {
this.currentTotal+=1;
return (
<p>InitialToal: {this.initialTotal}</p>
<p>Current Total: {this.currentTotal}</p>
);
}
}
You could create a stateful component and store the initial total in the component state.
Example
class MyView extends React.Component {
state = {
initialTotal: this.props.total
};
render() {
const { total } = this.props;
const { initialTotal } = this.state;
return (
<div>
<p> Total: {total} </p>
<p> Initial total: {initialTotal} </p>
</div>
);
}
}
class App extends React.Component {
state = {
total: 10
};
componentDidMount() {
this.interval = setInterval(() => {
this.setState(({ total }) => {
return { total: total + 1 };
});
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return <MyView total={this.state.total} />;
}
}
If I understand your requirements correctly...
function MyView(props) {
// if you only need to set the value once on load just use useState.
// the const total will be the value you pass in to useState.
const [total, setTotal] = useState(props.data.loading ? 0 : props.data.total)
// if its possible that the value is not available on initial load and
// you want to set it only once, when it becomes available, you can use
// useEffect with useState
useEffect(() => {
// some condition to know if data is ready to set
if (!props.data.loading) {
setTotal(props.data.total)
}
}, [props.data.total, setTotal, props.data.loading]
// this array allows you to limit useEffect to only be called when
// one of these values change. ( when total changes in this case,
// as the const function setTotal will not change
// ( but react will fuss if its used and not in the list ).
return (
<p> {total} </p>
);
}
I have the same need. With a functional component, I need to store the inital snapshot of states, let user play with different state values and see their results immediately, eventually, they can just cancel and go back to the initial states. Apply the same structure to your problem, this is how it looks:
import React from 'react';
import { useEffect, useState } from "react";
const TestView = (props: { data: any }) => {
// setting default will help type issues if TS is used
const [initialTotal, setInitialTotal] = useState(props.data.total)
useEffect(() => {
// some condition to know if data is ready to set
setInitialTotal(props.data.total);
// Critical: use empty array to ensure this useEffect is called only once.
}, [])
return (
<div>
<p> { initialTotal } </p>
<p> { props.data.total } </p>
</div>
);
}
export default TestView
You can use getDerivedStateFromProps life cycle method.
static getDerivedStateFromProps(props, state){
if(props.data.total && (props.data.total==10)){
return {
total : props.total // show total only when its 10
}
}else{
return null; // does not update state
}
}

ReactJS How to add additional image To props and change them on Click

Hello im trying to add an second image to my image props and change them on click any suggestions how can i solve it? here is my bin
my react bin
Your image src needs to be listening for a state and not a props. Props is immutable and State is mutable.
Below is an example of how you can do this.
import React from 'react'
import { render } from 'react-dom'
import { CSSTransitionGroup } from 'react-transition-group'
class FadeImage extends React.Component
{
constructor(props, context, images)
{
super(props);
this.state = {
index: 0,
imageClass: 'image'
};
this.fadeImage = this.fadeImage.bind(this);
}
fadeImage(e)
{
e.preventDefault();
var s = {
index: (this.state.index + 1) % this.props.images.length
};
if (this.state.imageClass === 'image')
{
s.imageClass = "image-loaded";
}
else
{
s.imageClass = "image";
}
this.setState(s);
console.log('clicked');
}
render()
{
return (
<div>
<a href="#" onClick={this.fadeImage}>Change Me!</a>
<img src={this.props.images[this.state.index]} />
</div>
)
}
}
render(<FadeImage images={['http://via.placeholder.com/350x150', 'http://via.placeholder.com/350x151']} />, document.querySelector('#app'))
Note that its perfectly fine to keep image paths in props. But you do need to have a current image index in state. Also there is no need to call setState multiple times. You can prepare your updates as part of one object and introduce all of them at once.
You need to pass an array of images as props.
render(<FadeImage images={["http://via.placeholder.com/350x150", "http://via.placeholder.com/350x151"]} />, document.querySelector('#app'))
And you update piece of state (currentImage) that doesn't exists. Change it to :
this.setState({
index: (this.state.index +1) % this.props.images.length
});
And if will work.
Here is your Bin.

Categories

Resources