React function binding is not working on nodejs - javascript

I have code:
var React = require('react');
class MasterLayout extends React.Component {
constructor(props) {
super(props);
console.log("I am constructor");
this.getComponent = this.getComponent.bind(this);
this.testMethod = this.test.bind(this);
this.testMethod();
}
test() {
console.log("test method called");
}
getComponent(ev) {
console.log('li item clicked!');
event.currentTarget.style.backgroundColor = '#ccc';
}
render() {
return (
<div>
<h3 id={this.props.id} onClick={this.getComponent}>qqqqqqqqqqqqqqqqqqqq</h3>
</div>
)
}
};
module.exports = MasterLayout;
When I run node server and go to localhost page, page is rendered sucesfully without any errors.
After click on h3 element nothing happens.
When is pagge loaded i am getting in console:
I am constructor
test method called
After click on h3, nothing happens. Whats wrong is with my code?
EDIT:
onclick="console.log('The link was clicked.'); return false"> too NOT working.

<h3 id={this.props.id} onClick={this.onClick}>CLICK ME</h3>
Unless I'm missing something you don't have an onClick method in MasterLayout
Are you sure you don't mean to create an onHeaderClicked (example) method in MasterLayout, bind it in the constructor, and use that instead of this.onClick?

Change your test() method to be named onClick():
var React = require('react');
class MasterLayout extends React.Component {
constructor(props) {
super(props);
console.log("I am constructor");
this.getComponent = this.getComponent.bind(this);
this.testMethod = this.test.bind(this);
this.testMethod();
}
onClick() {
console.log("test method called");
}
getComponent(ev) {
console.log('li item clicked!');
event.currentTarget.style.backgroundColor = '#ccc';
}
render() {
return (
<div>
<h3 id={this.props.id} onClick={this.onClick}>CLICK ME</h3>
</div>
)
}
};
module.exports = MasterLayout;
or if you are trying to invoke the getComponent() method change it in your render code to use that:
render() {
return (
<div>
<h3 id={this.props.id} onClick={this.getComponent}>CLICK ME</h3>
</div>
)
}
Or if you want to invoke both, call the 2nd method in the first method call function block:
getComponent(ev) {
console.log('li item clicked!');
event.currentTarget.style.backgroundColor = '#ccc';
this.onClick();
}

Nothing happens when you click on h3 because after you click you will get an error that cannot read property currentTarget of undefined as you are receiving the event parameter as ev and using it as event
You need to modify your getComponent method to
getComponent(ev) {
console.log('li item clicked!');
ev.currentTarget.style.backgroundColor = '#ccc';
}

Related

React: TypeError: this.setState is not a function

While trying to set value in Parent Class from value fetched from Child. I am getting the following error:
TypeError: this.setState is not a function
Parent Class
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {
favoritecolor: "ParentValue RED"
};
}
nameParent(e) {
this.setState({favoritecolor: e})
console.log(e); // I am getting the value here from Child. But how to use setState ?
}
render() {
let variableName = '';
return (
<div>
<h1>Value from Child is {this.state.favoritecolor}</h1>
<Child nameFn={this.nameParent}/>
</div>
);
}
}
export default Header;
Child Class
export class Child extends React.Component {
onHClick(e) {
this.props.nameFn(e);
}
render() {
return (
<h1 onClick = {this.props.nameFn('Blue Black Green')}>
Value from parent is = {this.props.name}
</h1>
)
}
}
Because of this I am unable to use setState to update state.
There are two errors, the first one is related to this usage in the Header component. You can replace
nameParent(e) {
by
nameParent = (e) => {
to scope this to the class level.
The second error is caused by the Child component because it directly invokes the provided function:
<h1 onClick = {this.props.nameFn('Blue Black Green')}>
It should be refactored to the following to fix the error:
render() {
return (
<h1 onClick = {() => this.props.nameFn('Blue Black Green')}>
Value from parent is = {this.props.name}
</h1>
)
}
Bind the function to the this of the class:
<Child nameFn={this.nameParent.bind(this)}/>

React component of grandparent callback doesnt re-render page after being call in grandchild

I am calling a handle method (to change state) in a <grandchild> component but it stop rendering after a couple of callback in the <grandparent> component.
I have tried to:
setting bind correctly with both this.bind in construct and arrow method.
making sure the call back is call everytime the prop.callback is call.
This is an example of what I'm trying to do with graphql server:
Grandparent Component
//Graphql constant for query
const ApolloConstant = gpl`
...etc
class Grandparent extends Component {
constructor(props) {
super(props);
this.state = { vars: 'query_string' }
}
handler = (args) => {
this.setState({vars: args})
}
render() {
return (
// For requerying graphql with search
<input onChange={() => this.setState(vars: e.target.value)} />
<Query variable={this.state.vars}>
...code -> some_data_arr
{<ChildComponent data={some_data_arr} handler={this.handler}/>}
</Query>
);
}
}
Child Component
//This component will take in an arr of obj and display a obj list
// if one of the obj is clicked then render a child component to display that single obj
class Child extends Component {
constructor(props) {
super(props);
this.state = {
singleData: null
}
}
render() {
return (
// Ternary operator here for conditional rendering
{
this.state.singleData
? <Grandchild data={this.state.singleData} handleParentData={this.props.handler} />
: this.display_data(this.props.data)
}
);
}
//Method to call to display objects
display_data = () => {
this.props.map() =>
<div onClick={this.setState({singleData: data})} > ...some code to display data <div/>
}
}
Grandchild Component
class Grandchild extends Component {
render() {
return (
{...do some code with object props here}
<Button onclick={(this.props.handleParentData(vars))} >Btn</Button>
);
}
}
When I test this, everything works for the first 3-4 render then no more re-rendering even though the callback is going through. I check to see if the method in <grandparent> is being call and it does but the state stop changing. Even after going to a new route (react router) and then coming back, I still cant change state with that callback.
<Button onclick={(this.props.handleParentData(vars))} >Btn</Button>
I think the problem is the function being called right into the onclick prop, you should probably have it wrapped in another function so it is only called when you actually trigger the onclick listener:
handleClick = () => {
this.props.handleParentData(vars)
}
render() {
return (
{...do some code with object props here}
<Button onclick={(this.handleClick)} >Btn</Button>
);
}

React Button onClick pass arguments

I am trying to call a function after the button has been clicked, which is possible so far but I have problems in passing the argument.
This is my first React App so bear with me.
In the this part the onClick event calling the "clickedQuickreply()" wont work
It fires a "TypeError: Cannot read property 'value' of undefined"
export function showMessage() {
console.log("Show Message");
let timeStamp = messages.giveTimestamp("not set");
let listItems = messageList.map(d => (
<p className={d.senderId} key={d.senderId}>
{" "}
{d.text}{" "}
</p>
));
let listreply = quickReplyList.map(d => (
<button
className="quickReplyButton"
key={d.id}
value={d.qrText}
**onClick={clickedQuickreply(this.value)}**
>
<span> {d.qrText} </span>
</button>
));
return (
<div>
<div className="timestamp">{timeStamp}</div>
<ul>{listItems}</ul>
<div className="quickreply">{listreply}</div>
</div>
);
}
export function clickedQuickreply(e) {
console.log("Clicked", e);
quickReplyList.length = 0;
//send.sendMessageToServer(query);
}
This is the code where it renders. Named App.js "main"
Normally I wanted to do the re-rendering everytime a fetch Request has completed, but my React understanding is not that far I guess.
class MessageDisplay extends React.Component {
constructor(props) {
super(props);
this.state = null;
}
componentDidMount() {
window.addEventListener("click", this.tick.bind(this));
window.addEventListener("keypress", this.tick.bind(this));
}
componentWillUnmount() {
window.removeEventListener("click", this.tick.bind(this));
window.removeEventListener("keypress", this.tick.bind(this));
}
componentDidUpdate() {}
tick() {
this.forceUpdate();
}
render() {
setTimeout(() => {
this.forceUpdate();
}, 2000);
return (
<div className="chatBox">
<ui.showMessage />
</div>
);
}
}
So how do you pass an argument in that situation for example?
Thanks for your time and patience.
You should write onClick={clickedQuickreply(this.value)} as onClick={clickedQuickreply}. React will execute the function by passing it the event object as argument internally.
One more thing I notcied here is that, you no need to export the function clickedQuickreply, as it can be private used as callback function as you did now by attaching it with the onClick props. So write it without export and define it inside the showMessage function.

Warning: setState(…): Cannot update during an existing state transition

I'm developing a simple 'to do list' react app (new to React.js). I have adding items to a list working but deleting items raises a question. Within my parent react component, i have the following code:
import ToDoEntries from './to_do_entries.jsx';
class ToDoList extends React.Component {
constructor(props) {
super(props);
this.state = { list: [] }
this.add = this.addItem.bind(this);
this.removeItem = this.removeItem.bind(this);
}
addItem(e) { //removed to avoid tl:dr }
render() {
return(
<form onSubmit={this.add}>
<input placeholder='Enter item' type='text' ref={(el) => {this._input = el;} }/>
<button>Add</button>
</form>
<ToDoEntries entries={this.state.list}
removeCallback={this.removeItem}
/>
);
}
}
My to_do_entries.jsx component:
class ToDoEntries extends React.Component {
constructor(props) {
super(props);
}
renderItems() {
const { entries, removeCallback } = this.props;
function createTasks(item) {
return <li key={item.key}>{item.text}</li>
}
var listItems = entries.map(function(item) {
return(<li onClick={removeCallback} key={item.key}>{item.text}</li>)
})
return listItems;
}
render() {
var todoEntries = this.renderItems();
return(
<ul>
{todoEntries}
</ul>
);
}
}
export default ToDoEntries;
Running this code bring:
Warning: setState(…): Cannot update during an existing state
transition
Question:
why does to_do_entries.jsx's render immediately execute the callback when an item gets added i.e:
var listItems = entries.map(function(item) {
return(<li onClick={removeCallback(id)} key={item.key}>{item.text}</li>)
})
However, adding .bind(null, id) to removeCallback ie. <li onClick={removeCallback.bind(null, id)} /> does not?
Problem is in this part:
onClick={removeCallback(id)}
We need to pass a function to onClick, not the value. When we use () with functionName, that means you are calling that method and assigning the result of that to onClick, that will create a infinite loop if you do setState in removeCallback, because of this cycle:
render -> removeCallback() -> setState ->
^ |
| |
| |
-----------------------------------------
That's why you are getting the error.
Check the snippet for difference between abc and abc():
function abc(){
return 'Hello';
}
console.log('without () = ', abc); //will return the function
console.log('with () = ', abc()); //will return the function result (value)
Why it is working with onClick={removeCallback.bind(null, id)}?
Because bind will create a new function, and assign that function to click event, here removeCallback will get called when you click on any item not automatically.
As per MDN Doc:
The bind() function creates a new bound function (BF). A BF is an
exotic function object (a term from ECMAScript 2015) that wraps the
original function object. Calling a BF generally results in the
execution of its wrapped function.
Check the React DOC: Handling events in JSX.
Check this answer for more details about bind: Use of the JavaScript 'bind' method
I would advise against that, and use a similar approach to the example I have written for you. Render a list of todo's that is bind-ed to state and then pass in the relevant information back up to your parent component to remove the item. In this case, I use the index of the todo to splice the array so that it removes it.
Your current onClick is invoked immediately when each todo <li> is rendered because it's simply a function call which is causing the problem. .bind solves this problem because it will create a new function when you click on the element which is why the function doesn't invoke immediately.
However, this is generally considered bad practice because every time the component it'll create this function again and again and again. Multiple this by the amount of todo's on the screen and you'll be losing performance. It's a small issue, but my example shows how to solve this problem.
https://codepen.io/w7sang/pen/VWNLJp
// App
class App extends React.Component{
constructor(props) {
super(props);
this.state = { list: [] }
this.add = this.addItem.bind(this);
this.removeItem = this.removeItem.bind(this);
}
addItem(e) {
e.preventDefault();
this.setState({
list: [
...this.state.list,
{
key: Math.random(1,10000),
text: this._input.value
}
]
})
}
removeItem(payload){
this.setState({
list: [
...this.state.list.slice(0, payload.index),
...this.state.list.slice(payload.index + 1)
]
})
}
render() {
return(
<div>
<form onSubmit={this.add}>
<input placeholder='Enter item' type='text' ref={(el) => {this._input = el;} }/>
<button>Add</button>
</form>
<ToDoEntries entries={this.state.list} removeItem={this.removeItem} />
</div>
);
}
}
// TodoEntries [STATELESS]
const ToDoEntries = ({ entries, removeItem } ) => {
return(
<ul>
{ entries.map((item, index) => {
return(<Todo key={item.key} index={index} item={item} removeItem={removeItem} />)
}) }
</ul>
);
}
// Todo
class Todo extends React.Component {
constructor(props){
super(props);
this.state = {};
this.remove = this.remove.bind(this);
}
remove() {
const { index, removeItem } = this.props;
removeItem({
index
});
}
render() {
return <li onClick={this.remove}>{this.props.item.text}</li>
}
}
ReactDOM.render(<App />,document.getElementById('app'));
<div id="app"></div>
why does to_do_entries.jsx's render immediately execute the callback?
Well, when your mapping over the list of todo's each <li/> is invoking the removeCallback function instead of assigning it to the onClick.
So current code
<li onClick={removeCallback(id)} </li>
is equivalent to:
var result = removeCallback(id);
<li onClick={result} </li>
You have correctly pointed out that using bind will work. This is due to the behavior which makes it so useful in these situations.
See the mdn docs for more info, but I'll quote the important part here:
bind ... creates and returns a new function that, when called...
In your case, when using bind, and giving that to the onClick you are creating a new function that will be called when the click event is actually fired, not when the element is being rendered.
Another way of looking at removeCallback.bind(null, id) is its like this:
var newFunc = () => {
return removeCallback(id);
}
<li onClick={newFunc} </li>

Reactjs pass html element on onclick

I'm new to React and I'm trying to pass the HTML element from an onClick event, but I'm not getting the expected result.
Here is the code:
import React, { Component } from 'react';
export class Header extends Component{
isScrolledIntoView (e){
console.log('html element is ',e)
}
render(){
return(
<div>
<button onClick={this.isScrolledIntoView.()}>Click me</button>
</div>
);
}
}
The desired output would be to get the button's HTML element in the console.
You need to capture the target of the e (event) instead of the event itself, like this:
import React, { Component } from 'react';
export class Header extends Component {
isScrolledIntoView (e) {
console.log('html element is ', e.target)
}
render() {
return (
<div>
<button onClick={this.isScrolledIntoView.bind(this)}>Click me</button>
</div>
);
}
}
Here is a demo link: https://codesandbox.io/s/y8xXqopM7
Hope it helps!
The method isScrolledIntoView() is bound to the class, not the component instance, so when you refer to this.isScrolledIntoView() in your render method it will return undefined. Regular React lifecycle methods are bound to the component instance, but for your own custom methods you need to do a little work, you can put it in the constructor:
constructor(props) {
this.isScrolledIntoView = this.isScrolledIntoView.bind(this);
}
Or you can use class properties to auto-bind the method:
isScrolledIntoView = (e) => {
// do stuff
}
2 things you need to change in your code.
1- You have to bind your isScrolledIntoView, and it could be inside your constructor, or doin' this => <button onClick={this.isScrolledIntoView.bind(this)}>Click me</button>
2- You should target your e event instead of only log e you should
=> console.log('html element is ', e.target)
Nice reading for novices in react
Passing current element using ref
class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null,
};
}
render() {
return (
<button className="square"
onClick={function(ref) { console.info(" click : " + ref.target.innerHTML); }}>
{this.props.value}
</button>
);
}
}
Credits : https://stackoverflow.com/ about using "ref"

Categories