I'm new to react.js and I'm trying to math.random a number and put it in this.props.firstCard property, but it returns undefined. I tried some variables but only result is undefined or syntax error. Code:
handleClick() {
let firstCard = this.state.isFirstCardChosen;
function chooseCard() {
return Math.floor(Math.random() * (80 - 1) + 1);
}
if (firstCard == false) {
this.props.firstCard = chooseCard;
console.log(this.props.firstCard);
}
}
What's wrong with this one? Thanks in advance.
I'm going to hazard a guess and suggest that
if:
the problem isn't just one caused by the fact you are trying to mutate props (props are immutable).
and:
You're using ES2015 class syntax
then
the problem may be that your handleClick method isn't properly bound to the component state so the call to this.props returns undefined.
To solve this you can bind the handleClick in the constructor as follows:
constructor (props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
As everyone else has said the props is immutable. Also make sure you are setting props correctly and binding your handleClick function in your constructor i.e:
constructor(props) {
super(props);
his.handleClick = this.handleClick.bind(this);
}
Related
image here Hi I am trying to get my click Power variable to double when function Upgrade is called however nothing is happening. Can anyone tell me why?
You need to make it this.clickPower *= 2 (in the Upgrade function), with the equals in order to alter the value of the variable.
You forgot to set an equal. The upgrade return is going nowhere, because upgrade is used as an onClick callback.
Using this.clickPower is not a good idea. If you want to initialize it in the render function, because it is not a props, state or ref.
React is rerendering following props and state, so you should set your clickPower in a state if you want to use it properly.
You should better initialize upgrade out of the render function.
// Not event callback mode :
let clickPower = 1;
function upgrade(value) => {
return value * 2;
}
clickPower = upgrade(clickPower);
// As callback but not in a React App
this.clickPower = 1;
function upgrade(e) => {
this.clickPower *= 2;
}
// Good way
constructor(props) {
super(props);
this.state = { clickPower: 1 };
}
function upgrade(e) => {
this.setState({ clickPower: this.state.clickPower * 2});
}
Plus :
const { money, setMoney } = this.props;
i'm newbie in react. i want to toggle value with checkbox. but i have an error Cannot read property 'checked' of undefined. the code is as follows:
import Form from 'react-bootstrap/Form'
class JobList extends Component{
constructor(props){
super(props)
this.state = {
full_time:false
}
this.handleCheckBox = this.handleCheckBox(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleCheckBox(event) {
this.setState({
full_time:event.target.checked
})
}
handleSubmit(event) {
console.log(this.state.full_time)
event.preventDefault();
}
render() {
return(
<div>
<Form onSubmit={this.handleSubmit}>
</Form>
<Form.Check aria-label="option 1" checked={this.state.full_time} onChange={this.handleCheckBox} />
</div>
)
}
i try using many answer in this forum, but none of them solve my problem. does anyone can help me ? thank you
You have forgot to bind this with you function and calling it on constructor of your component.
So when in your handleCheckBox you are passing this so this does not have target property so it will return undefined.
this.handleCheckBox = this.handleCheckBox(this) // issue is here
To solve this bind function as below:-
this.handleCheckBox = this.handleCheckBox.bind(this)
In React v16 (and older), the event object doesn't hang around after the function returns. Remember that React state updates are asynchronous, and so the event object has likely been nullified and returned back to the event pool*. Save the checked value before enqueueing the state update. You are also missing the this binding in the constructor, either fix that or convert to arrow function so this of the class is bound automatically.
handleCheckBox = (event) => {
const { checked } = event.target;
this.setState({
full_time: checked,
});
}
* Note: This is no longer the case in React v17.
Events
Note:
As of v17, e.persist() doesn’t do anything because the SyntheticEvent
is no longer pooled.
The problem i have is that React does not update in the situation below.
I added a forceUpdate() when the component should update just to make extra sure.
The code is simple so there is not much to say.
It's as if React does not see that it should update or am i doing something really wrong here?
class Greetings extends React.Component{
constructor(props){
super(props)
this.switchLanguage = this.switchLanguage.bind(this)
this.state = {
languageID: 0,
}
this.arrayContainingRenderValues = [
<span>{this.props.greetingArray[this.state.languageID]}!</span>,
<span>No greetings for you!!</span>
]
}
switchLanguage(){
this.setState((previousState) => ({languageID: (previousState.languageID + 1) % this.props.greetingArray.length}))
this.forceUpdate()
}
componentDidMount(){
this.timerID = setInterval(this.switchLanguage, 500)
}
componentWillUnmount(){
clearInterval(this.timerID)
}
render(){
return this.arrayContainingRenderValues[0]
//The return below works without problem
return <span>{this.props.greetingArray[this.state.languageID]}!</span>
}
}
let content = <Greetings greetingArray={["Good morning","Bonjour","Buenos días","Guten tag","Bom dia","Buongiorno"]}/>
ReactDOM.render(content, document.getElementById('root'))
The state gets updated, you can see that simply by commenting out the first return.
A i got an answer, it is just that the value of the content in this.arrayContainingRenderValues[] was computed and then fixed when first assigned inside the constructor(), to have it recompute the array had to be reassigned in the render().
So in the end i may as well not use the array at all. But i just wanted to test how react works thanks for the help.
The first time my array is rendered it is in the correct order, however, if it is changed the rendered order remains the same.
For example:
construct() {
this.state = {
test_array: [1,2,3,4]
}
let self = this;
setTimeout(function(){
self.scramble();
}, 5000);
}
scramble() {
this.state.test_array = [3,1,2,4];
this.setState(self.state);
}
render() {
this.state.test_array.forEach(function(item){
console.log(item);
});
return (
<div>
{this.state.test_array}
</div>
);
}
Results in:
On the console (the current order, correct):
3
1
2
4
Rendered as DOM (the original order, incorrect):
1
2
3
4
Any idea why this is failing to render in the correct order?
You were very close. Here's a few things I changed to fix it:
construct should be constructor
You always need to call super() as the first line of a constructor. (You don't really need to worry about this, it's an Object Oriented thing; google it if you're curious)
Use "arrow functions" instead of "keyword functions" or .bind(this) to prevent this from changing contexts
Do not modify this.state; always call this.setState if you want it to change
class OrderThing extends React.Component {
constructor() {
super()
this.state = {
test_array: [1,2,3,4]
}
setTimeout(() => {
this.scramble();
}, 5000);
}
scramble() {
this.setState({
test_array: [3,1,2,4]
});
}
render() {
this.state.test_array.forEach(function(item){
console.log(item);
});
return (
<div>
{this.state.test_array}
</div>
);
}
}
const div = document.createElement('div')
document.body.appendChild(div)
ReactDOM.render(<OrderThing />, 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>
A few suggestions here.
First of all, there is no construct() in js, but there is constructor().
Secondly, you should always call super method with props as an argument in constructor, like this:
constructor(props) {
super(props);
...
}
Finally, react developers highly recommend to modify state only using setState() method.
So you should rewrite your scramble method.
scramble() {
this.setState({test_array: [3,1,2,4]});
}
This changes should help you a little bit.
I have a class in which I bind some functions in the constructor. This works fine and as expected
class Row {
constructor(props) {
super(props)
this.onEditRowClick = this.onEditRowClick.bind(this)
this.onCommitRowClick = this.onCommitRowClick.bind(this)
this.onDeleteRowClick = this.onDeleteRowClick.bind(this)
this.onCellChange = this.onCellChange.bind(this)
}
...
}
however, if I change to
class Row {
constructor(props) {
super(props)
let handlers = [this.onEditRowClick, this.onCommitRowClick, this.onCellChange, this.onDeleteRowClick]
handlers.forEach(handler => {handler = handler.bind(this)})
}
...
}
it is clearly not working as I get exceptions indicating that this in my function invocations is null.
I thought arrow functions implemented a lexical this binding?
Also, if I do this
class Row {
constructor(props) {
super(props)
[this.onEditRowClick, this.onCommitRowClick, this.onCellChange, this.onDeleteRowClick].forEach(handler => {handler = handler.bind(this)})
}
}
I get
Uncaught TypeError: Cannot read property 'forEach' of undefined
while this is totally fine
[1,2,3].forEach(function(item){console.log(item)})
Maybe Im missing something very obvious and it's time for me to go to bed?
Function.prototype.bind() creates new function from the existing one which is bound to the passed context. Therefore you reassign properties in your first working example:
this.onEditRowClick = this.onEditRowClick.bind(this);
However in your latter example you skipped the reassign phase.
To solve this you can iterate over method names, bind it to the this instance and reassign:
class Row {
constructor(props) {
super(props);
let handlers = [
'onEditRowClick',
'onCommitRowClick',
'onCellChange',
'onDeleteRowClick'
];
handlers.forEach(handler => {
this[handler] = this[handler].bind(this);
});
}
...
}