Pop up alert when input is empty in react - javascript

I have asked this question many times here but didn't get the answer properly or any complete result. i need to validate my input or i can do that when my input tag is empty or when there is no number in the input, the alert should pop up. I tried for an alert but don't know why it is not working. Please help i'm stuck in this since a week.
Code:
<script type="text/jsx">
var styles = {
margin: '2em auto',
width: '300px',
height: '300px',
backgroundColor: '#DD4814',
color: '#ffffff',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'space-around'
};
var inputs = {
position: 'relative',
bottom: '17%',
left: '20%'
}
var btns = {
position: 'relative',
bottom: '7%'
}
var btn = {
backgroundColor: '#ffffff',
color: '#000000',
borderColor: '#DEB887',
borderRadius: '0.4em',
cursor: 'pointer',
margin: '0 1em',
padding: '0.5em',
display: 'inline-block'
}
var required = true;
class Timer extends React.Component {
constructor (props) {
super(props)
this.state = {count: 0, customNumber: 0}
}
handleChange (e) {
this.setState({ customNumber: e.target.value});
}
componentWillUnmount () {
clearInterval(this.timer)
}
tick () {
if (this.state.customNumber) {
this.setState({
count: (this.state.customNumber--)
})
if (this.state.customNumber <= 0) {
this.setState({ count: 0})
clearInterval(this.timer)
this.setState({ disabled: false })
}
} else {
this.setState({count: (this.state.count - 1)})
}
}
display () {
return ('0' + this.state.count % 100).slice(-2)
}
startTimer () {
if ((this.state.inputValue == " ") && isNaN(this.state.inputValue))
{
alert("Please give some value in number");
}
clearInterval(this.timer)
this.timer = setInterval(this.tick.bind(this), 1000)
this.setState({ disabled: true })
}
stopTimer () {
clearInterval(this.timer)
}
resetTimer () {
clearInterval(this.timer)
this.setState({count: 0})
this.setState({ disabled: false })
}
render () {
return (
<div style={styles} className='timer'>
<h1 style={{fontSize: '4em'}}>{this.display()}</h1>
<div className="input_text" style={inputs}>
<label htmlFor="custom_number">Enter number to start timer</label>
<input type="text" name="custom_number" id="custom_number" required={required} value={this.state.inputValue} onChange={this.handleChange.bind(this)} disabled={this.state.disabled} placeholder="Enter b/w 1-100" />
</div>
<div style={btns} className="buttons">
<button style={btn} type="button" name="start_btn" id="start_btn" onClick={this.startTimer.bind(this)}>Start</button>
<button style={btn} type="button" name="stop_btn" id="stop_btn" onClick={this.stopTimer.bind(this)}>Pause</button>
<button style={btn} type="button" name="reset_btn" id="reset_btn" onClick={this.resetTimer.bind(this)}>Stop</button>
</div>
</div>
)
}
}
ReactDOM.render(
<Timer />,
document.getElementById('root')
)
</script>
<div id="root"></div>

First thing, using alerts is not the best way to get the user's attention. console.log() is much more effective if all you are doing is debugging your code
Second thing, you are asking for alerts in a timer loop - you could end up with hundreds of alerts this way (refer to my first point)
Third thing, you are checking the value of this.state.inputValue and comparing it to a string containing one space (" ") which doesn't seem right
Fourth thing, you are setting the value of your input field with this:
value={this.state.inputValue}
This basically means the value of the field is set and can't be changed. You probably want to use defaultValue instead
Five, and I'm stopping here, your handleChange method doesn't even set the state, so you will never get what you want anyway.

Related

Show/Hide React Component based on State

I am very new to React and am trying to create a page where clicking on the color square will show the hex code for that color. I've tried a bunch of different things and I can't figure out if my problem is in the event handling, in the state handling, both, or in something else altogether. I can get the hex code to either be there or not, but not have it change when I click.
Here is my main:
<main>
<h1>Dynamic Hex Code Display</h1>
<div id="container"></div>
<script type="text/babel">
class ColorSquare extends React.Component {
render() {
var blockStyle = {
height: 150,
backgroundColor: this.props.color,
};
return <div style={blockStyle} onClick = {this.props.onClick}></div>;
}
}
class HexDisplay extends React.Component {
render() {
var hexText = {
fontFamily: "arial",
fontWeight: "bold",
padding: 15,
margin: 0,
textAlign: "center",
};
var hexTextVis = {
...hexText,
visibility: "visible"
}
var hexTextInvis = {
...hexText,
visibility: "hidden"
}
var isVisible = this.props.isVisible;
if (isVisible) {
return <p style={hexTextVis}>{this.props.color}</p>;
} else {
return <p style={hexTextInvis}>{this.props.color}</p>;
}
}
}
class HexParent extends React.Component {
constructor(props) {
super(props);
this.state = {
isVisible: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
this.setState(currentVis => ({isVisible: !currentVis.isVisible}));
console.log(this.state);
console.log('clicking');
}
render() {
var fullBoxStyle = {
padding: 0,
margin: 10,
backgroundColor: "#fff",
boxShadow: "3px 3px 5px #808080",
boxRadius: "5px 5px",
height: 200,
width: 150,
};
var buttonStyle = {
width:150,
backgroundColor: this.props.color
}
return (
<div style={fullBoxStyle}>
<span onClick={(e) => this.handleClick()}>
<ColorSquare color={this.props.color} />
<span style={{
isVisible: this.state.isVisible ? "true" : "false",
}}>
<HexDisplay color={this.props.color} />
</span>
</span>
</div>
);
}
}
ReactDOM.render(
<div class="colorRow">
<HexParent color="#ba2c9d" />
<HexParent color="#2cba90" />
<HexParent color="#2c9dba" />
</div>,
document.querySelector("#container")
);
</script>
When the object is created, it's a hexTextVis object. When you click, isVisible changes, but it's still a hexTextVis object and so the render doesn't change. You could either do something like:
<HexDisplay visibility={state.isVisible}/>
or
{state.isVisible ? <div/> : <HexDisplay />}
style={{
isVisible: this.state.isVisible ? "true" : "false",
}}
There isn't a css property with this name. Perhaps you meant to use visibility?
style={{
visibility: this.state.isVisible ? "visible" : "hidden"
}}
Try wrapping the span and and using a ternary operator to render the span element, based on if the condition of isVisible is equal to true, otherwise it should not return anything
{this.state.isVisible && <span><HexDisplay /></span>}

React How to use different states with click event

In short:
I'm implementing Simon-Says game app in React Native. (user sees a sequence of flashing buttons, needs to press the buttons in the correct order).
I want to know how to use 2 different states in TouchableOpacity, one of them as a condition to press the button, one for changing the style of the button, and also being notified for this specific press.
So,
I'm having a problem to implement the playerTurn(),
because I'm not sure how to pass the canPress state to the TouchableOpacity button,
considering I'm passing style state that changes in compTurn()
(function that shows a sequence of flashing buttons - then computer turn's over)
In the player turn, things I need to consider:
after the state canPress changes, the user will be allowed to press on the buttons
user presses one of the 4 buttons
the method playerTurn() will be notified which button did the player pressed. (I'm asking how can I get that notification from the button to the method?)
after that, I can push it's choice to the playerSeq array (if pressed green - pushes 1, etc) and call function that changes the style state (greenFlash for example)
code in short :
export default class App extends Component{
constructor (props){
super(props);
this.seq=[1,2,3,1,4] //will be random, this is just for testing
this.playerSeq=[]
...
this.state = {
canPress: false,
greenB: {
backgroundColor: 'darkgreen'
}, ...
playerTurn(){
this.setState({canPress: true})
// if the user pressed on the green button, then I push 1 to the playerSequence
// More functionality will be here
}
render(){
return (..
<TouchableOpacity style={[styles.greenB, this.state.greenB]}></TouchableOpacity>
//I ALSO WANT TO PASS THE STATE CANPRESS + NOTIFY PLAYERTURN() THAT THE USER PRESSED ON THIS BUTTON
Full code: (not the full game, note that I'm learning react just in the past few days)
export default class App extends Component{
constructor (props){
super(props);
this.flash=0
this.round=1
this.seq=[1,2,3,1,4] //will be random, this is just for testing
this.playerSeq=[]
this.win=false
this.ok=true
this.score=0
this.state = {
canPress: false,
greenB: {
backgroundColor: 'darkgreen'
},
yellowB: {
backgroundColor: 'orange'
},
blueB: {
backgroundColor: 'blue'
},
redB: {
backgroundColor: 'red'
}
}
this.play=this.play.bind(this)
this.greenFlash=this.greenFlash.bind(this)
this.blueFlash=this.blueFlash.bind(this)
this.redFlash=this.redFlash.bind(this)
this.playerTurn=this.playerTurn.bind(this)
}
play(){
this.flash=0
this.round=1 //round will increase, this is just for test
this.win=false
this.ok=true
this.score=0
this.compTurn();
this.playerTurn();
}
playerTurn(){
this.setState({canPress: true})
}
compTurn() {
let intervalId = setInterval(()=> {
if (this.flash==this.round) {
clearInterval(intervalId);
}
else {
if (this.seq[this.flash]==1){
this.greenFlash();
}
if (this.seq[this.flash]==2){
this.yellowFlash();
}
if (this.seq[this.flash]==3){
this.blueFlash();
}
if (this.seq[this.flash]==4){
this.redFlash();
}
this.flash++;
}
}
, 1500);
}
greenFlash(){
setTimeout(() => {
this.setState( {
greenB:{
...this.state.style1, backgroundColor: 'lightgreen'
}
})
}, 200);
setTimeout(() => {
this.setState( {
greenB:{
...this.state.style1, backgroundColor: 'darkgreen'
}
})
}, 1000);
}
yellowFlash(){
setTimeout(() => {
this.setState( {
yellowB:{
...this.state.style1, backgroundColor: 'yellow'
}
})
}, 200);
setTimeout(() => {
this.setState( {
yellowB:{
...this.state.style1, backgroundColor: 'orange'
}
})
}, 1000);
}
blueFlash(){
setTimeout(() => {
this.setState( {
blueB:{
...this.state.style1, backgroundColor: 'lightblue'
}
})
}, 200);
setTimeout(() => {
this.setState( {
blueB:{
...this.state.style1, backgroundColor: 'blue'
}
})
}, 1000);
}
redFlash(){
setTimeout(() => {
this.setState( {
redB:{
...this.state.style1, backgroundColor: 'pink'
}
})
}, 200);
setTimeout(() => {
this.setState( {
redB:{
...this.state.style1, backgroundColor: 'red'
}
})
}, 1000);
}
render(){
return (
<View>
<TouchableOpacity style={styles.playB}
onPress={this.play}>
<Text style={{
color:'white',
height: 30,
width:60,
}}>START</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.greenB, this.state.greenB]}></TouchableOpacity>
<TouchableOpacity style={[styles.yellowB, this.state.yellowB]}></TouchableOpacity>
<TouchableOpacity style={[styles.blueB, this.state.blueB]}></TouchableOpacity>
<TouchableOpacity style={[styles.redB, this.state.redB]}></TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
greenB:{
padding: 5,
height: 80,
width: 80,
borderRadius:160,
},
yellowB:{
padding: 5,
height: 80,
width: 80,
borderRadius:160,
},
blueB:{
padding: 5,
height: 80,
width: 80,
borderRadius:160,
},
redB:{
padding: 5,
height: 80,
width: 80,
borderRadius:160,
},
playB:{
alignSelf: 'center',
backgroundColor: 'blue',
}
});
Looks like you want to enable clicking on the buttons if state.canPress = true right? Then upon clicking, you wish to notify by calling playerTurn()?
You can do something like this for e.g your green button.
<TouchableOpacity style={[styles.greenB, this.state.greenB]} onPress={this.state.canPress && () => {
this.playerTurn(1);
// Whatever you want to do on green button pressed by player in here.
}>
</TouchableOpacity>
this.setState also has a callback function as its second parameter, which may be more useful in your flash method.

How to fix translate which contains state, which changed by 'interval' (React)

I have a procedure for a timer for animation. I want to make an animation of logos like https://stripe.com/us/customers. But I have an endless loading of the page, so it doesn't work.
I tried to use a procedure in different parts of the code and tried to change interval for better optimization (I think my PC can't work with 1 ms interval), but it didn't help me.
It all from one file.
State:
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
submitError: false,
width: 0,
height: 0,
timer: 0
};
Procedure:
TimeForLogos() {
const time = setInterval(() => {
const passedTime = this.state.timer + 0.1;
if (passedTime === 20) {
clearInterval(time);
}
this.setState({
timer: passedTime,
});
}, 100);
}
I try to use it in render (I need that procedure begins when the site is opened) and try to make a button (I thought it help me to solve the problem of endless loading). So part of code from render for now:
<div className={s.logos}>
<span onClick={this.TimeForLogos()}>go</span>
{LogoData.map(logo => (
<div
className={s.logo}
style={{
right: `${logo.positionX}px`,
top: `${logo.positionY}px`,
width: logo.width * 1.1,
padding: `${(logo.width - logo.height) / 2} 0`,
transform: `translate(${this.state.timer * 10}px,0) scale(1)`,
}}
>
<img
src={logo.img}
alt=""
style={{
width: logo.width,
height: logo.height,
}}
/>
</div>
))}
</div>
So, a question. How can I update my code that it works? And I need to make so that procedure works when the site is opening (animation must play when the site is opened). How I can do it?
You can create a separate component and handle the transition of each component in the timeout function.
class Home extends Component {
constructor(props) {
super(props);
this.logoData = [{
width: 100,
height: 100,
text: "text1"
},
{
width: 100,
height: 100,
text: "text2"
},
{ width: 100,
height: 100,
text: "text3"
}];
}
render() {
return (
<div className="mainContainer">
{this.logoData.map(item => <MovingDiv {...item}/>)}
</div>
);
}
}
Creating one more react-component say MovingDiv.
class MovingDiv extends Component {
constructor(props) {
super(props);
this.state = {
translateX: 0,
translateY: 0,
scale: 0
}
}
componentDidMount() {
const intervalLimit = setInterval(() => {
let { translateX, translateY} = this.state;
// logic of setting translateX goes here
if(--translateX < -300) { // -300 is just for example
translateX = 0;
}
this.setState({
translateX
})
}, 200)
}
/* will move the divs towards right every 200ms*/
render() {
return(<div style={{ width: this.props.width, height: this.props.height, transform: `translate(${this.state.translateX}px, 0px)`}}>{this.props.text}</div>);
}
}
Hope this helps!
I updated something in code of previous commentator. I make everything in one class (Home). I make json file for logos and info contains in this file. So it's my code.
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
translateX: 0,
};}
render() {
setInterval(() => {
let { translateX } = this.state;
translateX -= 2;
if (translateX < -1800) {
translateX = 0;
}
this.setState({
translateX,
});
}, 1000);
<div className={s.logos}>
{LogoData.map(logo => (
<div
className={s.logo}
style={{
left: `${logo.positionX}px`,
top: `${logo.positionY}px`,
width: logo.width * 1.1,
padding: `${(logo.width - logo.height) / 2} 0`,
transform: `translate(${this.state.translateX}px,0) scale(1)`,
}}
>
<img
src={logo.img}
alt=""
style={{
width: logo.width,
height: logo.height,
}}
/>
</div>
))}
</div>

SetTimeout runs twice, only if the component is reconstructed

So this is very weird. First of all here's part of my code responsible for the timeouts:
constructor(props) {
super(props);
this.state = {
assignments: [],
answers: [],
uploadedFile: '',
showTimeoutModal: false,
};
this.onImageDrop = this.onImageDrop.bind(this);
this.startCountDown = this.startCountDown.bind(this);
this.handleTimeoutButtonClick = this.handleTimeoutButtonClick.bind(this);
}
componentDidMount() {
clearTimeout(this.state.timer);
firebase.database().ref('Works').child(this.props.assignmentId).once('value', () => {
// var startTime = r.val().acceptedDate.time;
var startTime = Time.generate().time; //todo change to db specific time
var waitingTime = Time.makeMinutes(5);
var endTime = Time.generate().time + waitingTime;
this.setState({timer: this.startCountDown(startTime, endTime)});
}).catch(e => console.log(e));
}
componentWillUnmount() {
clearTimeout(this.state.timer);
}
startCountDown(startTime, endTime) {
var timeout = setTimeout(function () {
var now = startTime;
console.log(endTime - now);
if (now >= endTime) {
clearTimeout(timeout);
console.log(true);
this.setState({showTimeoutModal: true});
} else {
now = Time.generate().time;
this.setState({timer: this.startCountDown(now, endTime)});
}
}.bind(this), 1000);
return timeout;
}
handleTimeoutButtonClick() {
var startTime = Time.generate().time;
var waitingTime = Time.makeMinutes(0.15);
var endTime = Time.generate().time + waitingTime;
this.setState({showTimeoutModal: false, timer: this.startCountDown(startTime, endTime)});
}
The way my project works is: A user picks a task to solve. I don't fully understand React yet so I don't fully know what's going on in the background. But the fact is, when I construct the component for the first time, all goes well. When I leave the component to a different route, all works as well. But if I recreate this component it all breaks.
Here's the full component:
import React from 'react';
import firebase from '../../firebase';
import {Col, Button, Modal} from 'react-bootstrap';
import Dropzone from 'react-dropzone';
import CancelAnswerButton from '../answer/CancelAnswerButton';
import FinishAnswerButton from '../answer/FinishAnswerButton';
import AnswerComponent from '../answer/AnswerComponent';
import MetaTags from 'react-meta-tags';
import {Redirect} from 'react-router';
import './AssignmentComponent.css';
import 'font-awesome/css/font-awesome.min.css';
import Time from '../globalMethods/Time';
export default class AssignmentComponent extends React.Component {
async componentWillMount() {
firebase.database().ref('Users').child(firebase.auth().currentUser.uid).on('value', snap => {
if (snap.val().assignedWork) {
this.setState({hasAssignedTask: true});
} else {
this.setState({hasAssignedTask: false});
}
});
const assignmentsRef = firebase.database().ref('Works').orderByChild('firebaseKey').equalTo(this.props.assignmentId);
await assignmentsRef.on('value', snapshot => {
var assignments = snapshot.val();
var newState = [];
for (let assignment in assignments) {
let currentAssignment = assignments[assignment];
newState.push({
id: assignment,
category: currentAssignment.category,
level: currentAssignment.level,
pointAmount: currentAssignment.pointAmount,
pointBoost: currentAssignment.pointBoost,
points: currentAssignment.pointBoost + currentAssignment.pointAmount,
photoURL: currentAssignment.photoURL,
workText: currentAssignment.workText,
answers: currentAssignment.answers,
});
}
var answers = [];
for (let answer in newState[0].answers) {
let currAns = newState[0].answers[answer];
answers.push({
id: answer,
textAnswer: currAns.textAnswer,
downloadURL: currAns.downloadURL,
})
}
this.setState({
assignments: newState,
answers: answers,
});
});
}
constructor(props) {
super(props);
this.state = {
assignments: [],
answers: [],
uploadedFile: '',
showTimeoutModal: false,
};
this.onImageDrop = this.onImageDrop.bind(this);
this.startCountDown = this.startCountDown.bind(this);
this.handleTimeoutButtonClick = this.handleTimeoutButtonClick.bind(this);
}
componentDidMount() {
clearTimeout(this.state.timer);
firebase.database().ref('Works').child(this.props.assignmentId).once('value', function () {
// var startTime = r.val().acceptedDate.time;
var startTime = Time.generate().time; //todo change to db specific time
var waitingTime = Time.makeMinutes(5);
var endTime = Time.generate().time + waitingTime;
this.setState({timer: this.startCountDown(startTime, endTime)});
}.bind(this)).catch(e => console.log(e));
}
componentWillUnmount() {
clearTimeout(this.state.timer);
}
startCountDown(startTime, endTime) {
var timeout = setTimeout(function () {
var now = startTime;
console.log(endTime - now);
if (now >= endTime) {
clearTimeout(timeout);
console.log(true);
this.setState({showTimeoutModal: true});
} else {
now = Time.generate().time;
this.setState({timer: this.startCountDown(now, endTime)});
}
}.bind(this), 1000);
return timeout;
}
handleTimeoutButtonClick() {
var startTime = Time.generate().time;
var waitingTime = Time.makeMinutes(0.15);
var endTime = Time.generate().time + waitingTime;
this.setState({showTimeoutModal: false, timer: this.startCountDown(startTime, endTime)});
}
async onImageDrop(files) {
await this.setState({
uploadedFile: files[0],
});
await AnswerComponent.handleImageSubmit(files[0], this.props);
}
render() {
return (
this.state.assignments.map(assignment => {
return (
this.state.hasAssignedTask ?
<section key={assignment.id} className='display-assignment'>
<MetaTags>
<title>Zadanie</title>
</MetaTags>
<div style={{height: '150px', background: '#fff', borderBottom: '2px solid #e0e0e0'}}>
<div className='container'>
<h4 style={{
paddingTop: '75px',
fontSize: '24px',
textAlign: 'left'
}}>Aktualnie rozwiązywane zadanie</h4>
</div>
</div>
<div className='wrapper show-grid task_info container-fluid task_solve_content'>
<Col xs={12} md={6}>
<img className='task_img' alt='' src={assignment.photoURL}/>
<p>{assignment.workText}</p>
</Col>
<Col xs={12} md={6}>
<div className='row task_info_content'>
<div className='col-sm-4 col-md-4 col-lg-4'>
<h3 className='text-center gradient_text'>
{assignment.category}
</h3>
<h4 className='text-center'>przedmiot</h4>
</div>
<div className='col-sm-4 col-md-4 col-lg-4'>
<h3 className='text-center gradient_text'>
{assignment.level}</h3>
<h4 className='text-center'>poziom</h4>
</div>
<div className='col-sm-4 col-md-4 col-lg-4'>
<h3 className='text-center gradient_text'>
{assignment.points}</h3>
<h4>punkty</h4>
</div>
</div>
<form encType="multipart/form-data">
<textarea placeholder='Wpisz rozwiązanie...' name="textAnswer" id="textAnswer"
style={{
width: '100%',
height: '80vh',
background: 'white',
color: 'black',
}}/>
<div style={{width: '100%', height: '60px', position: 'relative'}}>
<Button className="send_text_answer_button"
onClick={() => AnswerComponent.handleTextSubmit(this.props)}
style={{display: 'block'}}>
<span>Wyslij odpowiedź tekstową</span>
</Button>
</div>
<Dropzone
className='dropzone'
multiple={false}
accept='image/*'
style={{
backgroundColor: '#fff',
border: '1px solid #fff',
borderBottom: '2px solid #e0e0e0',
borderRadius: '4px',
width: '100%',
height: '300px',
marginBottom: '20px'
}}
onDrop={this.onImageDrop.bind(this)}>
<i className='fa fa-image' style={{
fontSize: '64px',
marginRight: '5px',
color: '#e0e0e0',
margin: 'auto',
marginTop: '120px'
}}/>
</Dropzone>
<h3 style={{display: 'none', color: 'red'}}
id='error'>Upewnij sie ze dodana jest przynajmniej jedna odpowiedz!</h3>
<div id='answers'>
<h3 style={{
fontSize: '18px',
fontWeight: 'lighter',
marginTop: '10px',
marginBottom: '10px'
}}>Odpowiedzi przeslane do tej pory</h3>
{
this.state.answers.map(answer => {
return (
<Col xs={12} md={12} key={answer.id}>
{
answer.textAnswer !== undefined &&
answer.textAnswer.length > 0 ?
<div className='task_info_text_answer'>
<p>{answer.textAnswer}</p>
</div>
:
<img className="your_answer_img"
src={answer.downloadURL}
alt=""/>
}
<br/>
<Button className="delete_answer_button"
onClick={() => AnswerComponent.removeAnswer(this.props, answer.id)}>
<span>Usuń odpowiedź</span>
</Button>
</Col>
)
})
}
</div>
<div className="row" style={{marginTop: '50px', marginBottom: '100px'}}>
<div className="col-sm-6 col-md-6 col-lg-6 cancel_answer_button_content"
style={{height: '200px'}}>
<CancelAnswerButton className="send_text_cancel_answer_button"
points={assignment.pointAmount + assignment.pointBoost}
assignmentId={assignment.id}/>
<div className="cancel_answer_button_info">
<p>Za anulowanie zadania grozi odjęcie punktów z rangi!</p>
</div>
</div>
<div className="col-sm-6 col-md-6 col-lg-6 finish_answer_button_content"
style={{height: '200px'}}>
<FinishAnswerButton className="send_text_finish_button"
points={assignment.pointAmount + assignment.pointBoost}
assignmentId={assignment.id}/>
<div className="finish_answer_button_info">
<p>Upewnij się, że uczeń dostał wszystko, czego potrzebuje!</p>
</div>
</div>
</div>
</form>
</Col>
</div>
<Modal show={this.state.showTimeoutModal}>
<Modal.Header>
Hej! Rozwiazujesz dalej to zadanie?
</Modal.Header>
<Modal.Body>
<h3>Pozostaly czas: {this.state.timeLeft / 1000}</h3>
<Button className='btn btn-primary' onClick={this.handleTimeoutButtonClick}>Tak! Daj
mi jeszcze 5 minut! </Button>
</Modal.Body>
</Modal>
</section>
:
<Redirect to='/assignments'/>
)
})
)
}
}
So how can I make the timer run just once? What am I missing?
Logs in the console after the first click:
300000 AssignmentComponent.js:89
298999 AssignmentComponent.js:89
297997 AssignmentComponent.js:89
296996 AssignmentComponent.js:89
295994 AssignmentComponent.js:89
294992 AssignmentComponent.js:89
293990 AssignmentComponent.js:89
292988 AssignmentComponent.js:89
291986 AssignmentComponent.js:89
290984 AssignmentComponent.js:89
289983 AssignmentComponent.js:89
Logs after the second click:
300000 AssignmentComponent.js:89
298993 AssignmentComponent.js:89
298999 AssignmentComponent.js:89
297992 AssignmentComponent.js:89
297997 AssignmentComponent.js:89
296990 AssignmentComponent.js:89
296996 AssignmentComponent.js:89
295981 AssignmentComponent.js:89
295993 AssignmentComponent.js:89
294980 AssignmentComponent.js:89
294991 AssignmentComponent.js:89
Also I just realized, it doesn't only run twice. It starts a new timer, for each click. So if you recreate the component 5 times, there will be 5 timers running next to each other.
Here's what I did for my app.
Add a timer variable in the constructor, assign the setTimeout function to that timer variable wherever you want to start the timer. And clear timeout using that variable.
class TimerComponent extends Component {
constructor() {
super();
this.timer = null; //Timer initialisation
}
startTimeout = () => {
this.timer = setTimeout(() => {
}, 500)
}
componentDidMount() {
this.startTimeout();
}
componentWillUnmount() {
clearTimeout(this.timer); //Clearing timeout
this.timer = null;
}
}

React, update array's total count state when new item is added to it

I have my array where you can add a "player" to it and it updates just fine. I also have a total number of players that looks at the array and gives the total sum. It works but it does not factor in the new items.
I know I need to pass it the new updated state of the array (players) but I'm just stuck on how to do that.
I've provided snips of my code as follows
Array
const players = [
{
name: 'Jabba',
score: 10,
id: 11
},
{
name: 'Han',
id: 1
},
{
name: 'Luke',
id: 2
},
Function to add to the array
handleChange = e => {
this.setState({
newPlayerName: e.target.value
});
};
handleAddPlayer = e => {
this.setState(prevState => ({
players: [
...prevState.players,
{
name: this.state.newPlayerName,
id: getRandomInt(20, 155)
}
]
}));
};
my state
this.state = {
id: players.id,
totalScore: 0,
totalPlayers: players,
countInfo: [],
evilName: '',
color: '#6E68C5',
scoreColor: '#74D8FF',
fontAwe: 'score-icon',
incrementcolor: '',
scoreNameColor: 'white',
glow: '',
buttonStyle: 'count-button-start',
newPlayerName: '',
max_chars: 15,
chars_left: '',
players
};
And finally the function that should update the total but doesn't and where I'm stuck
function Stats(props) {
const totalPlayers = props.players.length;
const totalScore = props.players.reduce(
function(total, player) {
return props.totalScore + props.totalScore;
},
0
);
return (
<div style={{ width: '100%' }}>
<PlayerNumb>Number of players: <b>{totalPlayers}</b></PlayerNumb>
</div>
);
}
the const totalPlayers = props.players.length; is where I seemed to be tripped up. Any help would be greatly appreciated and apologies if I gave any confusing information as React is still new to me.
Also an example of how I called stats:
<Stats
style={{ width: '100%' }}
totalScore={this.state.totalScore}
players={players}
/>
And the complete render code of how Players is created
render() {
const listPlayers = this.state.players.map(player => (
<Counter
key={player.id}
player={player}
playersArray={this.state.players}
name={player.name}
sortableGroupDecorator={this.sortableGroupDecorator}
decrementCountTotal={this.decrementCountTotal}
incrementCountTotal={this.incrementCountTotal}
removePlayer={this.removePlayer.bind(this)} //bind this to stay in the context of the parent component
handleClick={player}
/>
));
return (
<ContainLeft style={{ alignItems: 'center' }}>
<ProjectTitle>Score Keeper</ProjectTitle>
<Copy>
A sortable list of players that with adjustable scores. Warning, don't go negative!
</Copy>
<GroupHolder>
<Stats
style={{ width: '100%' }}
totalScore={this.state.totalScore}
players={players}
/>
<div
style={{ width: '100%' }}
className="container"
ref={this.sortableContainersDecorator}
>
<div className="group">
<div className="group-list" ref={this.sortableGroupDecorator}>
{listPlayers}
</div>
</div>
</div>
<HandleForm>
<form
style={{ width: '100%' }}
onSubmit={this.handleClick.bind(this)}
>
<p className="sort-player">Add A Player</p>
<InputText
type="text"
maxLength="15"
max="4"
name="usr"
placeholder="Enter a new name"
value={this.state.newPlayerName}
onChange={this.handleChange}
/>
<PlayerButton onClick={this.handleAddPlayer}>
Press to Add Player
</PlayerButton>
<CharacterCount>
Characters left
{' '}
{this.state.max_chars - this.state.newPlayerName.length}
</CharacterCount>
</form>
</HandleForm>
</GroupHolder>
</ContainLeft>
);
}
}
export default Container;
You're calling your render function with an undefined variable called players
players={players}
You either need to pass this.state.players or define it with const players = this.state.players;
You should always be developing locally with an eslint plugin for your editor, which will highlight problems like these as syntax errors and save you hours of time.

Categories