New to react cannot access state. Can someone explain?
I am trying to create bar graphs on the board and then whenever the button is clicked I want to perform one iteration of a sorting algorithm. I need the logic for: whenever the button is clicked, then I want to re render the squares based on their heights.Can someone push me in the right direction?
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null,
heightSet: 3,
};
}
render() {
var divHeightStyle = {
height: this.props.heightSet + 'em',
};
return (
<button
id={this.props.value}
value={this.props.heightSet}
style={divHeightStyle}
className="square">
{this.props.value}
</button>
);
}
}
class Rectangle extends React.Component {
constructor(props){
super(props);
};
reccheck = () => {
this.props.check();
}
render(){
return (
<button
className="rectangle"
onClick={() => this.reccheck()} >
</button>
)
}
}
class Board extends React.Component {
constructor(props) {
super(props);
const min = 1;
const max = 80;
const rand = min + Math.random() * (max - min)
const rand1 = min + Math.random() * (max - min)
const rand2 = min + Math.random() * (max - min)
const rand3 = min + Math.random() * (max - min)
this.state = {
squares: [rand, rand1, rand2, rand3],
};
}
renderSquare(i, y) {
return <Square value={i} heightSet={y}/>;
}
check(){
if(this.state.squares[0] > this.state.squares[1]) {
alert('0 is bigger');
}
}
renderRectangle() {
return <Rectangle check={this.check}/>;
}
render() {
const status = '';
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(1,this.state.squares[0])}
{this.renderSquare(2,this.state.squares[1])}
{this.renderSquare(3,this.state.squares[2])}
{this.renderSquare(4,this.state.squares[3])}
</div>
{this.renderRectangle()}
</div>
);
}
}
class Game extends React.Component {
render() {
return (
<div className="game">
<div className="game-board">
<Board />
</div>
<div className="game-info">
<div>{/* status */}</div>
<ol>{/* TODO */}</ol>
</div>
</div>
);
}
}
// ========================================
ReactDOM.render(
<Game />,
document.getElementById('root')
);
When you call to a function like you are doing, you are using a different this. You should either bind the correct this or use an arrow function.
Binding:
renderRectangle() {
return <Rectangle check={this.check.bind(this)}/>;
}
or, arrow function:
check: () => {
if(this.state.squares[0] > this.state.squares[1]) {
alert('0 is bigger');
}
Related
I am trying to generate random number for test functionality to display in my Material UI Progress bar . This piece of JS code is working in JS fiddle.
But I want to show this random number with my reactJs.
Any help/suggestion how can I achieve this.
//Testcode
class TestPage extends React.Component {
constructor(props) {
super(props);
this.state = {
displayProgress: ""
}
}
displayProgress() {
this.setState(document.getElementById('out').innerHTML = Math.random() * 101 | 0);
}
render() {
const { displayProgress } = this.props;
const createProgress = setInterval(displayProgress, 1000);
return (
<div className="test">
<div id="out"></div>
<LinearProgress variant="determinate" value={createProgress} />
</div>
);
}
};
export default TestPage;
Accessing dom elements directly is not a good idea in react. this makes more sense:
class TestPage extends React.Component {
constructor(props) {
super(props);
this.state = {
progress : 0
}
}
componentDidMount(){
this.interval = setInterval(()=>{
this.displayProgress();
},1000)
}
componentWillUnmount(){
clearInterval(this.interval);
}
displayProgress = () => {
const prog = Math.random() * 101
this.setState({
progress : prog
})
}
render() {
return (
<div className="test">
<LinearProgress variant="determinate" value={this.state.progress} />
</div>
);
}
};
export default TestPage;
this should do it.
Upon clicking the submit button many things happen including cancelling the countdown clock. I am using setTimeout() and it actually works just fine, but for some reason I can no longer delete items. When I remove the setTimeout() deleting the items works just fine. I really have no idea what's going on as they are completely separate things and use completely separate variables.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import { Image } from './Image.js'
import { Button } from './Button.js'
import { images } from './assets/images.js'
import { Countdown } from './Countdown.js'
import { DisplayCount } from './DisplayCount.js'
import { Inputs } from './Inputs.js'
class Game extends React.Component{
constructor(props){
super(props)
this.timer = null
this.thoughts = []
this.thought = []
this.state = {
currentImg: 0,
timer: null,
ranNum: null,
thought: [],
isSubmitted: false
}
this.handleClick = this.handleClick.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
this.handleDeleteClick = this.handleDeleteClick.bind(this). < -------------
}
countdownClock = async (newRanNum) => {
const startingNum = newRanNum * 20;
for(let i = startingNum; i >= 0; i--) {
await new Promise(resolve => {
this.timer = setTimeout(() => {
this.setState({
timer: i
})
resolve()
}, 1000)
});
}
}
handleChange(event, index) {
const inputs = [...this.state.thought];
inputs[index] = event.target.value
this.setState({
thought: inputs
});
}
handleClick(){
clearTimeout(this.timer)
let newRanNum = Math.floor(Math.random() * 20);
this.countdownClock(newRanNum)
this.generateStateInputs(newRanNum)
// this.generateInputs(this.state.thought)
let current = this.state.currentImg;
let next = ++current % images.length;
this.setState({
currentImg: next,
ranNum: newRanNum
})
}
generateStateInputs(newRanNum){
let inputArray = []
for(let i = 0; i < newRanNum; i++){
inputArray.push('')
}
return this.setState({
thought: inputArray
});
}
handleSubmit(event) {
if(event){
clearTimeout(this.timer) <------------------------------------------
event.preventDefault();
let thought = this.state.thought.map(word => word + ' ');
console.log(thought)
this.thoughts.push(thought)
event.preventDefault()
this.setState({
thought: []
})
}
}
handleDeleteClick(index){ <-------------------------------------------------------
return this.thoughts = this.thoughts.filter(thought => thought !== this.thoughts[index])
}
render(){
let src = this.state.currentImg;
return(
<div>
<Countdown name={'Countdown: '} countdown={this.state.timer} />
<DisplayCount name='Word Count: ' count={this.state.ranNum} />
<Image src={images[src]} />
<Button onClick={this.handleClick} name='Generate Inputs' />
<form onSubmit={this.handleSubmit}>
<ol>
{this.state.thought.map((input, index) => (
<Inputs type='text' key={index} value={input} onChange={event => { this.handleChange(event, index) }} className='textInputs' />
))}
</ol>
<input type='submit' value='Submit' />
</form>
<div>
<ol>
{this.thoughts.map((thought, index )=>
<DisplayPoem key={index} onClick={() => { this.handleDeleteClick(index) }} name='Delete Thoughts' value={thought} /> <---------------------------------------------
)}
</ol>
</div>
</div>
)
}
}
class DisplayPoem extends React.Component {
render(){
return (
<li>
<span>{this.props.value}</span>
<button onClick={this.props.onClick}>{this.props.name}</button>
</li>
)
}
}
ReactDOM.render(
<Game />,
document.getElementById('root')
);
I am trying to generate inputs on a button click and the amount of inputs is generated by a random number. Here is what I have so far, but it isn't working. I am very confused and feel like it should be working. I am not sure what I am missing. Any help would be very much appreciated.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import { Image } from './Image.js'
import { Button } from './Button.js'
import { images } from './assets/images.js'
import { Countdown } from './Countdown.js'
import { DisplayCount } from './DisplayCount.js'
import { Inputs } from './Inputs.js'
class Game extends React.Component{
constructor(props){
super(props)
this.timer = null
this.state = {
currentImg: 0,
timer: null,
ranNum: null
}
this.handleClick = this.handleClick.bind(this)
}
countdownClock = async (newRanNum) => {
const startingNum = newRanNum * 20;
for(let i = startingNum; i >= 0; i--) {
await new Promise(resolve => {
this.timer = setTimeout(() => {
this.setState({
timer: i
})
resolve()
}, 1000)
});
}
}
generateInputs = (newRanNum) => {
const inputs = []
for(let i = 1; i <= newRanNum; i++){
inputs.push(
<Inputs type='text' className='textInputs' />
)
}
return inputs;
}
handleClick(){
clearTimeout(this.timer)
let newRanNum = Math.floor(Math.random() * 20);
this.countdownClock(newRanNum)
this.generateInputs(newRanNum)
let current = this.state.currentImg;
let next = ++current % images.length;
this.setState({
currentImg: next,
ranNum: newRanNum
})
}
render(){
let src = this.state.currentImg;
return(
<div>
<Countdown name={'Countdown: '} countdown={this.state.timer} />
<DisplayCount name='Word Count: ' count={this.state.ranNum} />
<Image src={images[src]} />
<Button onClick={this.handleClick} />
<div>
<ul>
{this.generateInputs()}
</ul>
</div>
</div>
)
}
}
ReactDOM.render(
<Game />,
document.getElementById('root')
);
Inputs component:
import React from 'react'
export const Inputs = (props) => {
return (
<li className={props.className}>
<input value={props.value} />
</li>
)
}
I believe the issue is here...
generateInputs = (newRanNum) ...
and here...
{this.generateInputs()}
You're input rendering function is expecting a parameter it's not getting, and since that returns as undefined the loop never runs. :)
In general, it is most common to separate state (eg, number of inputs) from the rendering, and only have the rendering respond to state. Perhaps you had originally intended generateInputs() to produce the array, and not render them (?)
The first thing is your generateInputs() function takes a parameter for number of inputs you wanted to render but you are not passing any parameter to this.generateInputs()
The second thing is you are returning an array from this function but not mapping your array in the render function, So do in this way.
this.generateInputs(10) // pass parameter here
this.generateInputs(10).map((item, index)=>item)
In this Snack, I have done the same thing but with react-native
https://snack.expo.io/#waheed25/smiling-carrot
This is my code:
import React, { Component } from 'react';
class Counter extends Component {
constructor(props){
super(props);
this.state = {
number : 0
};
this.handleIncrease = this.handleIncrease.bind(this);
this.handleDecrease = this.handleDecrease.bind(this);
}
handleIncrease = () => {
this.setState=({
number: this.state.number + 1
});
console.log("handleIncrease()");
}
handleDecrease = () => {
this.setState({
number: this.state.number - 1
});
console.log("handleDecrease()");
}
render(){
return (
<div>
<hr/>
<h1>Counter</h1>
<p>number : {this.state.number}</p>
<button onClick={this.handleIncrease}>+</button>
<button onClick={this.handleDecrease}>-</button>
<hr/>
</div>
)
}
}
export default Counter;
It works when I press the - button, but it does not work when I press the + button and I get an error:
TypeError: _this.setState is not a function
Counter._this.handleDecrease
Remove the equal sign:
handleIncrease = () => {
>>>> this.setState({
number: this.state.number + 1
});
console.log("handleIncrease()");
}
Also, pass a function in setState when using the previous state to set new state as state updates can be asynchronous.
More Info: https://reactjs.org/docs/state-and-lifecycle.html
import React, { Component } from 'react';
class Counter extends Component {
constructor(props){
super(props);
this.state = {
number : 0
};
this.handleIncrease = this.handleIncrease.bind(this);
this.handleDecrease = this.handleDecrease.bind(this);
}
handleIncrease = () => {
//here remove equal
this.setState({
number: this.state.number + 1
});
console.log("handleIncrease()");
}
handleDecrease = () => {
this.setState({
number: this.state.number - 1
});
console.log("handleDecrease()");
}
render(){
return (
<div>
<hr/>
<h1>Counter</h1>
<p>number : {this.state.number}</p>
<button onClick={this.handleIncrease}>+</button>
<button onClick={this.handleDecrease}>-</button>
<hr/>
</div>
)
}
}
export default Counter;
I wrote this code, but when I run it, I only get a blank page. What is wrong?
It does seem that I am close to the answer. I've tried everything, but it is still not working.
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
random: 0
}
}
render() {
var min = 1;
var max = 100;
var rand = min + (Math.random() * (max-min));
handleClick() {
this.setState ({this.state.random + this.rand})
}
return (
<div>
<button value="Click me!" onClick={this.handleClick.bind(this)></button>
</div>
);
React.render(<Button />, document.querySelector('#container'));
}
}
JSFIDLLE: https://jsfiddle.net/1cban4oy/12/
Remove all your logic from the render function and add it to the click handler method. Also the onClick is missing a curly bracket at the end. Finally you're not indicating the state property you're updating in the setState() method.
This basically seems to do what you're after:
https://codesandbox.io/s/98n9EkEOJ
This is the code just in case:
import React from 'react';
import { render } from 'react-dom';
class Button extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = { random: 0 };
}
handleClick() {
const min = 1;
const max = 100;
const rand = min + Math.random() * (max - min);
this.setState({ random: this.state.random + rand });
}
render() {
return (
<div>
<button onClick={this.handleClick.bind(this)}>Click</button>
<div>The number is: {this.state.random}</div>
</div>
);
}
}
render(<Button />, document.getElementById('container'));
Firstly, you didn't set the state properly.
Secondly, use arrow functions so you can avoid problematic binding.
Thirdly, you didn't display the random value anywhere.
Lastly - you can move the min and max variables outside the render function. Also the whole math logic responsible for rolling a random number can be moved into the handleClick function.
Working code:
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
random: null,
}
}
min = 1;
max = 100;
handleClick = () => {
this.setState({random: this.min + (Math.random() * (this.max - this.min))});
};
render() {
return (
<div>
<button onClick={this.handleClick}>Click me</button>
{this.state.random}
</div>
);
}
}
Try this:
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
random: null
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
const min = 1;
const max = 100;
const random = min + (Math.random() * (max - min));
this.setState({ random })
}
render() {
return (
<div>
<button value="Click me!" onClick={this.handleClick}>{this.state.random}</button>
</div>
);
}
}
React.render(<Button />, document.querySelector('#container'));
i think you need move this line
React.render(<Button />, document.querySelector('#container'));
not only from render method but even from the class.
and you need to do some changes
so your code be like :
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
random: 0
}
}
handleClick = () => {
var min = 1;
var max = 100;
var rand = min + (Math.random() * (max-min));
this.setState ({this.state.random : rand})
}
render() {
return (
<div>
<button value="Click me!" onClick={this.handleClick}> {this.state.random} </button>
</div>
);
}
}
React.render(<Button />, document.querySelector('#container'));
There is an easy way to create Random Number using
random-string
var x = randomString({
length: 8,
numeric: true,
letters: false,
special: false,
});
Here is the documentation for more details
random-string
Random number in an Array in React:
[Math.floor(Math.random() * 20)]
import React, { useState } from "react";
const App = () => {
const [num, setNum] = useState(0);
function randomNumberInRange(min, max) {
// get number between min and max
return Math.floor(Math.random() * (max - min + 1)) + min;
}
const handleClick = () => {
setNum(randomNumberInRange(1, 5));
};
return (
<div>
<h2>number is: {num}</h2>
<button onClick={handleClick}>Generate random number</button>
</div>
);
};
export default App;