Cannot read property 'checked' of undefined react checbox - javascript

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.

Related

Passing a parameter to an event handler in the parent class from a child class ReactJS

I am trying to pass a parameter to an event handler in a parent class, but am having some difficulty. I have done a good amount of research and am close to answer, but something's not quite working. Below I will give a basic hypothetical example of what I would like to do that doesn't work.
class Parent extends React.Component {
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(i){
return event => console.log(i);
}
render(){
return <Child onClick={this.handleClick}></button>;
}
}
class Child extends React.Component {
render() {
const myVar = 2;
return <button onClick={this.props.onClick(myVar)}></button>;
}
}
I know the onClick prop that is passed to the Child is not a function, so I am unable to pass parameters directly to it. What is the best way to go about doing this? Thanks for you help!
Make the following update to your code
class Child extends React.Component{
render(){
const var = 2;
return <button onClick={ () => {this.props.onClick(var)} }</button>;
}
}
Furthermore, you should refactor the following method used by parent as so. You are passing e needlessly.
handleClick(i){
console.log(i);
}
The onClick on your child component was immediately invoked instead of waiting for the onClick event to fire.
You can't do
handleClick(i){
return (e => {console.log(i)});
}
instead, try
handleClick(i){
console.log(i)
}
and move the event handling to where it is being called. So instead of
<button onClick={this.props.onClick(var)}</button>
You want to try
<button onClick={e => this.props.onClick(var)}</button>

reactjs input element loses focus after keystroke

So I am using a hash to store the values of dynamically created rows of input values and I lose focus on the input I am modifying after entering only one character. I think the solution to this may be to use refs to refocus on only the last input changed, but I couldn't get it to work, as I wasn't able to figure out how to specify which element was last changed. Advice on how to solve this is appreciated.
The code below dynamically creates input boxes, and looks up their values based on the unitPriceValueHash. Each variant has an id, and id is used as the key to the hash.
I created a codepen to try and recreate the problem, but the issue im facing doesn't show up in code pen. In my actual app I press 1 for example in the input box, then the cursor is not on the input box anymore.
https://codepen.io/ByteSize/pen/oogLpE?editors=1011
The only difference between the codepen and my code appears to be the fact the the inputs are nested inside a table.
CreateItem(variant) {
const unitPriceValueHash = this.props.unitPriceValueHash
return {
variant_title: variant.variant_title,
variant_price: variant.variant_price,
unit_cost: <TextField
type="number"
onChange={(event) => this.handleUnitPriceChange(variant.id, event)}
key={variant.id}
value={unitPriceValueHash[variant.id] || ''}
/>
};
}
Below is the change of state that modifies the hash
handleUnitPriceChange (id, event) {
const unitPriceValueHash = this.state.unitPriceValueHash
unitPriceValueHash[id] = event
console.log(unitPriceValueHash)
this.setState({unitPriceValueHash: unitPriceValueHash});
//this.updateVariantUnitCost(id, event);
}
There's a couple problems with the code you've shared.
Don't use inline functions. Each render, the function is created again which means that when react compares the props, it looks like the function is different (it is a new/different function each time!) and react will re-render.
Don't modify any objects which exist in the state, instead create a new object. If you modify an object that exists in the state, you're essentially saying you don't want renders to be consistent and reproducible.
I've re-posted your original code with the issues highlighted
CreateItem(variant) {
const unitPriceValueHash = this.props.unitPriceValueHash
return {
variant_title: variant.variant_title,
variant_price: variant.variant_price,
unit_cost: <TextField
type="number"
onChange={(event) => this.handleUnitPriceChange(variant.id, event)}
// ^^^^ - inline functions cause react to re-render every time, instead - create a component
key={variant.id}
value={unitPriceValueHash[variant.id] || ''}
/>
};
}
handleUnitPriceChange(id, event) {
const unitPriceValueHash = this.state.unitPriceValueHash
unitPriceValueHash[id] = event
// ^^^^ - please, please - don't do this. You can't mutate the state like this.
// instead, do the following to create a new modified object without modifying the object in the state
const unitPriceValueHash = Object.assign({}, this.state.unitPriceValueHash, { id: event });
this.setState({ unitPriceValueHash: unitPriceValueHash });
}
In regards to the inline-function, generally the recommendation is to create a new component for this which takes the value as a prop. That might look like this:
class UnitCost extends PureComponent {
static propTypes = {
variantId: PropTypes.number,
variantValue: PropTypes.object,
onUnitPriceChange: PropTypes.func,
}
handleUnitPriceChange(e) {
this.props.onUnitPriceChange(this.props.variantId, e)
}
render() {
return (
<TextField
type="number"
onChange={this.handleUnitPriceChange}
value={this.props.variantValue || ''}
/>
);
}
}
CreateItem(variant) {
const unitPriceValueHash = this.props.unitPriceValueHash
return {
variant_title: variant.variant_title,
variant_price: variant.variant_price,
unit_cost: (
<UnitCost
key={variant.id}
variantId={variant.id}
variantValue={unitPriceValueHash[variant.id]}
onUnitPriceChange={this.handleUnitPriceChange}
/>
),
};
}
Regarding your concerns about focus, react generally won't lose your object focus when re-rendering, so don't ever, ever re-focus an object after an update for this reason.
The only time react will lose focus, is if it completely discards the current DOM tree and starts over from scratch. It will do this if it thinks a parent object has been replaced instead of modified. This can happen because of a missing key prop, or a key prop that has changed.
You have not posted enough code for us to investigate this further. If you want more help you should build a minimum reproducible example that we can run and test.
The solution to this problem had me use an intermediate state to store the value of the input field on change, and a submit AJAX request on an onBlur
class TextFieldWrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
value: this.props.variantValue[this.props.variantId] || '',
}
this.handleUnitPriceChange = this.handleUnitPriceChange.bind(this)
this.updateValue = this.updateValue.bind(this)
}
updateValue(value){
this.setState({
value: value,
});
}
handleUnitPriceChange() {
this.props.onUnitPriceChange(this.props.variantId, this.state.value);
}
render(){
return (
<TextField
type="number"
id={this.props.variantId}
key={this.props.variantId}
onChange={this.updateValue}
onBlur={this.handleUnitPriceChange}
value={this.state.value}
/>
);
}
}

want to execute disNone() function inside saveInfo() function when click on button

I want to execute disNone() inside saveInfo() when the button is clicked:
Error:TypeError: Cannot read property 'disNone' of undefined
import React, { Component } from 'react';
class Login extends Component {
constructor(props){
super(props);
this.state = {
dispNone:"dispNone",
message:"dispNone"
};
this.disNone = this.disNone.bind(this);
};
disNone(){
this.setState({
dispNone: "dispNone",
message:"dispBlock"
});
}
saveInfo(){
this.disNone();
}
render() {
return (
<div>
// other code
<button onClick={this.saveInfo}>Sign up</button>
</div>
);
}
}
export default Login;
In the constructor, besides this.disNone = this.disNone.bind(this), you also need to put
this.saveInfo = this.saveInfo.bind(this);
the error is because safeInfo does not know what this means, which gives you the error that disNone is undefined
EDIT: We do this in the constructor because we only need to bind the function once. Alternatively you could write it in the render function as well, but that means everytime the render function executes, you rebind the the function which is kind of a waste.
A third alternative is to use the () => this.saveInfo() inside the render function, this does not require any kind of binding anywhere, but again, this function has to be "created" every time the render function runs.
add
this.saveInfo = this.saveInfo.bind(this);
in your constructor.
SaveInfo method is not having access to this.

In react.js ,why always throw ' setState(...): Can only update a mounted or mounting component...... error?

In the following code, on componentWillUnmount I remove the scroll event listener but the dev-tool always throws the following error:
setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the undefined component.
The code:
render () {
let opa=!this.state.opa?
{
backgroundColor:'#fff',
borderBottom:'.01rem solid #e8e8e8'
}:null;
return (
<div id='search' style={opa}>
<input type='text' placeholder=''/>
<div id='ser_scan'></div>
</div>
)
}
toggle_opa () {
let opa;
let _top=~~(document.body.scrollTop*100/parseInt(document.documentElement.style.fontSize,10))
opa=_top>=215?false:true;
console.log(1)
this.setState({opa})
}
componentDidMount() {
document.addEventListener('scroll',this.toggle_opa.bind(this));
}
componentWillUnmount() {
console.log(1231)
document.removeEventListener('scroll',this.toggle_opa)
}
what is wrong?
The problem is because you are using the bind method. It curries a new function, so the handler you add in didMount is different than the one you send to removeListener. You can use arrow function while defining the handler, like this -
toggle_opa =()=>{......}
Then simply pass toggle_opa to the add/remove Listener calls. No need for bind.
Your eventlistener is never properly removed, so I guess you get the error when you scroll after the component has unmounted.
First, make sure toggle_opa is always bound to this by adding a constructor function inside the component
constructor(props) {
super(props);
this.toggle_opa = this.toggle_opa.bind(this);
}
then you can add and remove eventlisteners like this:
componentDidMount() {
document.addEventListener('scroll',this.toggle_opa);
}
componentWillUnmount() {
console.log(1231)
document.removeEventListener('scroll',this.toggle_opa)
}

ReactJS bind a component method the correct way

I am trying to use .bind() when using a method in my component.
The reason is simple: In a loop I am returing Components and extend them with a property which is calling a method. But for every loop-item this I want to extend the this Object with some information (like a key).
Example:
Items.jsx
Items = React.createClass({
eventMethod() {
console.log('this event was triggered by key:', this.key);
},
items() {
let items = [];
let properties = {};
_.each(this.props.items, (itemData, key)=>{
properties.eventMethodInItem = this.eventMethod.bind(_.extend(this, {
key
}));
let {...props} = properties;
let item = <Item {...props} key={key} />;
items.push(item);
});
return items;
},
render() {
return(<div>{this.items()}</div>);
}
});
Item.jsx
Item = React.createClass(...);
In this case (and its working) when the Item Component is triggering the prop "eventMethodInItem" my method "eventMethod" will be called and this.key has the correct value!
So - whats now the question ? Its working perfect, right ?
Yes.
But ReactJS does not want me to do this. This is what ReactJS is telling me as a console log.
Warning: bind(): You are binding a component method to the component. React does this for you automatically in a high-performance way, so you can safely remove this call. See Items
Maybe you think its a "bad" way to add children to the component like I am doing it but in my special case I need to do this in this way - so I need to bind new information to a method.
I'm not going to pretend that I understand what you are trying to do here, but maybe I can help clear it up anyway.
React takes all of the top level methods found on each component and automagically binds them to the context of the component.
This prevents other methods from overriding the context of this and as a result, if you try to rebind the method, React says "Hey don't bother. I already got it" — which is the warning you are seeing.
Assuming that you really want do this (each time you are mutating the outer properties object by overriding the eventMethodInItem property).
properties.eventMethodInItem = this.eventMethod.bind(_.extend(this, {
key
}));
Then I can't see any reason that the eventMethod has to live on the component, rather than just in the scope of the items function.
items() {
const eventMethod = function() {
console.log('this event was triggered by key:', this.key);
}
// ...
_.each(this.props.items, (itemData, key)=>{
properties.eventMethodInItem = eventMethod.bind(_.extend(this, {
key
}));
// ...
});
},
That way you don't have to fight React to get your program to work.
React is already autobinding this when using React.createClass http://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html#under-the-hood-autobinding-and-event-delegation
Change your binding to
properties.eventMethodInItem = this.eventMethod.bind(null,key);
and your eventMethod to
eventMethod(key) {
console.log('this event was triggered by key:', key);
}
I also suggest using _.map instead of _.each
items() {
return _.map(this.props.items, (itemData, key) => {
return <Item
handleEventMethod={this.eventMethod.bind(null,key)}
key={key} />;
});
},
Good pattern
https://www.newmediacampaigns.com/blog/refactoring-react-components-to-es6-classes
Before :
class ExampleComponent extends React.Component {
constructor() {
super();
this. _handleClick = this. _handleClick.bind(this);
this. _handleFoo = this. _handleFoo.bind(this);
}
// ...
}
After :
class BaseComponent extends React.Component {
_bind(...methods) {
methods.forEach( (method) => this[method] = this[method].bind(this) );
}
}
class ExampleComponent extends BaseComponent {
constructor() {
super();
this._bind('_handleClick', '_handleFoo');
}
// ...
}
another good hacks for this topic http://egorsmirnov.me/2015/08/16/react-and-es6-part3.html

Categories