Can't bind anything: "Cannot call method "bind" of undefined" - reactjs

import React from 'react'
const Buttons = React.createClass({
getInitialState() {
return {clicks: 0}
},
countClicks() {
this.setState({
clicks: ++this.state.clicks
})
console.log(this.state.clicks)
}
render() {
return (
<div>
<div onClick={console.log("HEYYY")}>This should log "HEYYY"</div>
<div onClick=({this.countClicks()}>This should update clicks</div>
)
}
})
This will print "HEYYY" and 1 respectively on the first render but never do anything when actually clicked.
While this gave me some headache I found the solution in an example:
//Instead of doing this
<a onClick={this._changeValue(2)}>Change Value</a>
//Do this
<a onClick={this._changeValue.bind(2)}>Change Value</a>
Ah, perfect, I thought. Except that when I try it I get an error:
TypeError: Cannot call method 'bind' of undefined
I removed the simple console.log because I have no idea what to bind in it and went with countClicks() only, and I did get it somewhat working when I removed the parenthesis like so:
<div onClick=({this.countClicks.bind(this)})>This should update clicks</div>
First of all, why can't I bind something when I have the parenthesis in? Second, I instead got an ugly WARNING:
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.
Is React stupid?!
Or am I..?

My own solution:
render() {
const self = this
<div onClick={function() { self.countClicks() }}>This should update clicks</div>
}
No use of bind, no errors, no warnings.

Related

How to fire onSelectStart in React/JSX?

I'm familiar with the usage of selectstart event in HTML. I'm using onSelectStart in JSX. I expect it connects to onselectstart. But, it throws a warning saying that it's unknown.
Warning: Unknown event handler property `onSelectStart`. It will be ignored.
Example code:
function Example() {
return (
<div className="Example">
<h2 onSelectStart={() => console.log("Selection started")}>Click</h2>
</div>
);
}
I've tried this with react/react-dom#16.8.4 and react-scripts#3.0.1.
Is there an alternative for onSelectStart? If yes, how to implement the same?
Apparently https://reactjs.org/docs/events.html#selection-events not supported by react it seems. Even on MDN docs this dont seem to be standardized event: https://developer.mozilla.org/en-US/docs/Web/API/Document/selectstart_event#Specifications so I would question validity of its usage.
Here's the workaround using refs:
https://codesandbox.io/s/fancy-wave-sotun
ref={el => {
el &&
el.addEventListener("selectstart", () => {
console.log("Selection started");
});
}}
Just dont forget to remove Event listener on unmount of component.

Understanding React refs - why is my reference null here?

I have a use-case where a React ref makes sense.
I've tried a few different ways of implementing them, and in this case integrating them with hammerjs.
I'm mostly going off of this question:
adding hammerjs to a react js component properly
My return method in my render is as such:
return (
<div className={"App card-row card-color " + this.props.className} ref={
(el) => this._slider = el
}>
{this.state.bubblemsg ? (
<NotifBubble message={this.state.bubblemsg} merchant={this.props.merchant.merchant}/>
) : (
null
)}
<ScrollMenu
data={this.state.list}
inertiaScrolling={true}
transition={.1}
inertiaScrollingSlowdown={.000001}
/>
</div>
);
Which I would think would attach my div element as a reference.
In my componentDidMount() method, I am then attaching it to hammer:
componentDidMount() {
this.hammer = Hammer(this._slider)
this.hammer.on('swipeleft', console.log("swipe left"));
this.hammer.on('swiperight', console.log("swipe right"));
}
However, I am getting the error:
TypeError: Cannot read property 'addEventListener' of undefined
And this is directly related to Hammer, and thus the reference I assume.
So what am I doing wrong with my references? I don't totally understand how they're supposed to work and the React tutorial explanation wasn't super clear, so a thorough explanation would be useful.
I think the problem is that in the listening of the hammer you have to pass a function to be called, try inserting an arrow function to log
componentDidMount() {
this.hammer = Hammer(this._slider)
this.hammer.on('swipeleft', () => console.log("swipe left"));
this.hammer.on('swiperight', () => console.log("swipe right"));
}

When trying to .append() some JSX to the body, I get [object Object]...

I have a multiple field form, and I'm trying to get a small Form Warning to display when the user inputs wrong information. The problem I'm having is that the form will not display the warning under the desired input correctly. I have been told that this is because the Form warning is positioned absolutely, and thus and parents along that way that are not-staticly-positioned will throw off the alignment.
The recommendation was to use .append or .after in componentWillMount() to put the Form Warning component in the body, so FormWarning component can be positioned absolutely to the window. Makes sense to me, but my attempts only being me an [object Object] at the very bottom of my page.
Can anyone provide any insight into why this is occurring and what I can do to fix it? I've tried multiple different ways of putting this, but nothing works. I always just get [object Object]
componentWillMount(){
this.formWarningToBody();
}
formWarningToBody = () => {
let form =[]
form.push(<FormWarning visible={this.state.formWarning.visible}
invalidInputID={this.state.formWarning.invalidInputID} text=
{this.state.formWarning.text}/>)
document.body.append({form})
}
render() {
if (this.state.isSubmitted) return <Redirect to="/order" />
let CustomTag = this.props.labels ? 'label' : 'span',
{ inputs, saveInputVal, styles, state } = this,
{ formWarning, submitting } = state,
{ invalidInputID, text, visible } = formWarning
return (
<div style={this.styles.formWrapper}>
{
typeof this.props.headerText === 'string'
? ( <h2 style={this.styles.formHeader}>{this.props.headerText}</h2> )
: this.props.headerText.map((text) => {
return <h2 key={text} style={this.styles.formHeader} className={'header'+this.props.headerText.indexOf(text)}>{text}</h2>
})
}
<form onSubmit={this.submit} style={this.styles.form}>
<FormOneInputs inputs={inputs} saveInputVal={saveInputVal} CustomTag={CustomTag} styles={styles} />
<button style={this.styles.button}>{this.props.buttonText}</button>
</form>
<Throbber throbberText='Reserving your order...' showThrobber={submitting} />
</div>
)
}
}
That's not how React works, you can't just push JSX to DOM because a JSX element is indeed an object, which is then rendered to HTML. You can use React Portals.
See docs: https://reactjs.org/docs/portals.html

Why i cant return h1 element in reactJs onClick

I shorten my question, but now it look really silly, my main problem is i want to return html tag, in the question i am using just a literal string,
my function is working fine as console log is working fine,
seeing the output i understand is this, i am firing the function at the wrong place, but i am really confused about it.
Below is my code, Please read the comment with the code, and this not the actual problem, but i dont want to dump my full code here, again main problem console.log line is working but not the return line in the function
import React from 'react';
export default class Event extends React.Component {
onEdit()
{
console.log('it will return this'); **//This line work**
return 'Why i am not able to return this'; **//This one is not showing** why ??
}
render(){
return(
<div>
<button onClick={this.onEdit.bind(this)}>Edit</button>
</div>
);
}
}
Your function is definitely returning a string - It seems like you are very confused... You need to return jsx and trigger a re render if you expect this to appear in the DOM
here is an example of what I mean https://fiddle.jshell.net/46hbpmna/
You can make h1 with button props by adding role, for example:
_doSomething = () => {
console.log('asd')
}
<h1
className="item__title"
role="button"
onClick={() => this._doSomething()}
>
Your Title
</h1>
You need to add
retun ()=> your "title"
inside the html tag on onClick button.

Conditionally render list with Higher Order Component

My app has a feature toggle functionality that tells my UI whether or not a piece of UI should be rendered. I would like to create a Higher Order Component to conditionally render these types of components. In one scenario, I'm trying to conditionally render a list, but I'm running into this error:
ConditionalRender(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
This makes sense since I just am trying to render the children of this component. Here's what I've got so far:
https://jsfiddle.net/fmpeyton/cykmyabL/
var settings = { showHello: true, showGoodbye: false};
function ConditionalRender (props) {
var output = null;
if(props.shouldRender) output = props.children;
console.log(output);
// return (<li>{output}</li>); // This works, but isn't desired html structure
return ({output});
}
function App (props) {
return (
<ul>
<ConditionalRender shouldRender={props.settings.showHello}>
<li>Hello!</li>
</ConditionalRender>
<ConditionalRender shouldRender={props.settings.showGoodbye}>
<li>Goodbye...</li>
</ConditionalRender>
</ul>
);
}
ReactDOM.render(
<App settings={settings} />,
document.getElementById('container')
);
If I can help it, I would just like to render the children without any additional logic.This HOC would also handle more complex children down the line. Something like this:
<ConditionalRender shouldRender={props.settings.showHello}>
<div>
<p> blah blah blah</p>
<table>
<!-- ... -->
</table>
</div>
</ConditionalRender>
Any ideas?
Try this:
function App(props) {
return (
<ul>
{props.settings.showHello && <li>Hello!</li>}
{props.settings.showGoodbye && <li>Goodbye...</li>}
</ul>
);
}
P.S. Your code doesn't work because of this line:
return ({output});
Assuming you have es2015 support, it would be treated as object property shorthand. So it's the same as:
return {output: output};
which is not what React expects to get from the render method.
You could try this:
function ConditionalRender(props) {
if (props.shouldRender) {
// Make sure we have only a single child
return React.Children.only(props.children);
} else {
return null;
}
}
But this is not the simplest way. See more here.
P.P.S. Your ConditionalRender component is not what is called Higher-Order Component. According to the docs, HOC is a function that takes a component and returns a new component.

Resources