How to change text on mouse event in React - javascript

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 ?

Related

React: multiple components with the same event handler: trying to change the state of only the component which was clicked and not of all the others

I'm new to React and have to work on a specific assignment where all the logic of my app is in a single parent component and the child component only receives a few props. However, in the child there shouldn't be any logic or almost no logic.
I have a grid (parent component) made of 25 cell and each cell (child component ) can be either on or off. Imagine each cell as a light which is on or off.
From my parent component I'm rendering the cell component 25 times. Every time each cell has:
a key
an id
a status (on or off randomly assigned)
a click event
In my child component when the click event is triggered, the child component return to the parent its id and its status(on or off)
What I want to achieve:
In my parent component I want to be able to detect which child has been clicked and only change the status of the clicked child.
What I get so far:
Despite the parent receive the id and the status of the child that has been clicked, when I change the state via setState, all the children are affected.
Here is a snippet of my parent component:
import React, { Component } from 'react';
import GridSquare from './GridSquare';
import { randomlyLit, cellIdentifier } from '../helpers/helperFuns.js';
let nums = []
cellIdentifier(nums, 25)
class GridContainer extends Component {
static defaultProps = {
gridSize: 25
};
constructor(props) {
super();
this.state = {
cellID: nums,
hasWon: false,
lightStatus: Array.from({ length: 25 }, () => randomlyLit()),
};
this.changeValue = this.changeValue.bind(this);
}
changeValue(id, value) {
console.log(id, value);
this.setState(st => ({
// let result = st.cellID.filter(c => c===id)
// if(result){
// st.value = !value;
// }
lightStatus : !value
})
)
}
render() {
return (
<div>
<h1 className="neon">
Light <span className="flux">Out</span>
</h1>
<div className="GridContainer">
{this.state.cellID.map((el, i) =>(
<GridSquare key={this.state.cellID[i]} id={this.state.cellID[i]} lit={this.state.lightStatus[i]} click={this.changeValue}/>
))}
</div>
</div>
);
}
}
export default GridContainer;
Here is a snippet of my child component:
import React, {Component} from 'react';
class GridSquare extends Component {
constructor(props){
super(props);
this.handleClick= this.handleClick.bind(this)
}
handleClick(){
this.props.click( this.props.id, this.props.lit);
}
render() {
const squareClasses = {
'GridSquareOn': this.props.lit === true,
'GridSquareOff': this.props.lit === false,
'GridSquare': true,
}
function classNames(squareClasses) {
return Object.entries(squareClasses)
.filter(([key, value]) => value)
.map(([key, value]) => key)
.join(' ');
}
const myClassName = classNames(squareClasses)
return(
<div className={myClassName} onClick={this.handleClick}>
</div>
)
}
}
export default GridSquare;
My app.js only renders the parent component and nothing else:
import GridContainer from './components/GridContainer.jsx'
import './style/App.css';
import './style/GridContainer.css';
import './style/GridSquare.css';
function App() {
return (
<div className="App">
<GridContainer />
</div>
);
}
export default App;
Thank you in advance for any help!
changeValue(id, value) {
console.log(id, value);
this.setState(st => ({
// let result = st.cellID.filter(c => c===id)
// if(result){
// st.value = !value;
// }
lightStatus : !value
})
Your change value function is updating the state with the wrong value.
Initial value of your lightStatus is an array of booleans ( assuming randomlyLit function will return a boolean.
When you click on one of the cells, the lightStatus gets updated with the value of false instead of an array.
To fix this, search through the entire lightStatus array by index for which the cell was clicked and update the boolean at that particular index using Array.slice.
How to Optimise
Instead of traversing the whole array every time to update the lightStatus of the cell. You can save the the value in an Object.
What if I could update the status in changeValue like this ?
this.setState((st) => {
return {
...st,
lightStatus: { ...st.lightStatus, [id]: value } // Direct update without traversing through array
}
});
lightStatus can be used to form a "mapping" between cell ids in cellID and their corresponding status booleans.

ReactJS change background image dynamically doesn't work

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].

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.

Component state variable as img src url

I am new to React. I am trying to set the src attribute of an image using a component state variable. But when I run the code I don't see the component getting rendered. However if I explicitly define src url of the image, it works.
My code is as follows. I am also using React carbon component and react grid layout.
import 'carbon-components/scss/globals/scss/styles.scss';
import GridLayout from 'react-grid-layout';
import React, { Component } from 'react';
import { ClickableTile,Link } from 'carbon-components-react';
class ct extends React.Component {
constructor() {
super()
this.state ={
arr:[]
}
}
componentWillMount(){
let tilesData = []
fetch("https://xyz/api/abc")
.then((results)=>{
return results.json();
}).then((data)=>{
let details = {
imageUrl:data.images["image"]
}
tilesData.push(details)
this.setState({arr : tilesData})
})
render() {
var layout = [
{i: 'a', x: 0, y: 0, w: 2, h: 2}
];
return (
<GridLayout className="layout" layout={layout} rowHeight={30} width={50}>
<ClickableTile key="a">
<div>
// issue here ---------VVVVV
<img src={this.state.arr[0].imageUrl}/>
</div>
</ClickableTile>
</GridLayout>
);
}
}
What could be the issue?
UPDATE - I fixed the issue
FIX - this.state ={
arr:[{}]
}
}
Your fetch operation is asynchronous. You are changing the state without waiting for it to finish. You need to set the state in the fetch success callback for the setstate to take effect. Thus, your state is empty because the state was never changed.
Try this:
fetch("https://xyz/api/abc")
.then((results)=>{
return results.json();
}).then((data)=>{
let details = {
imageUrl:data.images["image"]
}
tilesData.push(details)
this.setState({arr : tilesData}) //call setState in the fetch callback
})
I fixed it
this.state =
{
arr:[{}]
}
}

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