How to access props within a component? - reactjs

Is it possible to access myVar value within handleClick? Still struggling to get the basics right :-). Tried passing it within {myVar} but still the same.
var Button = React.createClass({
getInitialState(){
return {counter: 1}
},
handleClick(){
console.log(this.props.myVar); //getting undefined here
},
render(){
return(
<button onClick={this.handleClick} myVar="blah">{this.state.counter}</button>
);
}
});

Props are available everywhere on your Component which means that there is no need for you to pass it as a prop to the button tag. Just a correctly bound function will take care of that for you and since you're using .createClass() your functions are automatically bound to the instance of your component meaning that
the handleClick function already has access to both this.props and this.state.
handleClick: function (event) {
console.log(this.props.myVar); //blah
}
But if you want to pass an extra variable to your function handleClick you need to pass a new function to your onClick handler. Remember to bind this so you have access to your instance as well
handleClick: function (event, myVar) {
console.log(myVar);
}
<button onClick={this.handleClick.bind(this, myVar)} />

A property is bound to the component itself, so this.props will always point to the properties added via the parent, and not each part of markup like angular directives. To bind a variable to the onclick, you can do it like this:
<button onClick={() => this.handleClick("blah")}>{this.state.counter}</button>
Then youre handleclick will fetch it as its first parameter.
You can of course create your own button-component, and then pass in props like you do. Then the button-component will contain this.props.myVar

You can bind the variable and access as a parameter in handleClick function :
var Button = React.createClass({
getInitialState(){
return {counter: 1}
},
handleClick(myVar){
console.log(myVar) //consoles blabh;
},
render(){
let myVar="blabh";
return(
<button onClick={this.handleClick.bind(myVar)} >{this.state.counter} </button>
);
}
});

The thing is that events are not bound to your component by default, so to fix that just bind the the handler to this.
<button onClick={this.handleClick.bind(this)} myVar="blah">{this.state.counter}</button>

Related

How to solve the lost binding issue for event handlers in React?

In React, it looks like for a self-contained component, we are still experiencing the "lost binding issue":
The following React code in CodePen to change a from 123 to 456 doesn't work:
class Foo extends React.Component {
state = { a: 123 };
clickHandler() {
this.setState({ a: 456 });
}
render() {
return (
<div>
<h1>Hello, world! {this.state.a} </h1>
<button onClick={this.clickHandler}>Click Me</button>
</div>
);
}
}
ReactDOM.render(
<Foo />,
document.getElementById('root')
);
It can be solved by
making it onClick={this.clickHandler.bind(this)}
making the handler an arrow function
Is there any other way to write the code to handle the lost binding issue or to make the issue go away altogher? Is it possible to do in the constructor or componentDidMount() to bind all the methods to itself, something like (pseudo code) so that the issue of lost binding can be gone as far as the component is concerned?
for (methodName of this.allMethodNames()) {
this[methodName] = this[methodName].bind(this);
}
If you want automatic binding you'll need to rewrite the onClick to something like this:
<button onClick={() => this.clickHandler()}>Click Me</button>
Otherwise you'll have to do it like this:
<button onClick={this.clickHandler.bind(this)}>Click Me</button>
One way around both of those is to use functional components where you could just pass the function with no issues. Here is your component turned into a functional component here: https://codesandbox.io/s/distracted-nobel-46wgf
import React, { useState } from "react";
import ReactDOM from "react-dom";
export default function Foo() {
const [state, setState] = useState({ a: 123 });
const clickHandler = () => {
setState({ ...state, a: 456 });
};
return (
<div>
<h1>Hello, world! {state.a} </h1>
<button onClick={clickHandler}>Click Me</button>
</div>
);
}
ReactDOM.render(<Foo />, document.getElementById("root"));
Your components needs a constructor, that's where binding is supposed to happen in class-based React:
class Foo extends React.Component {
// Set up your constructor and explicitly pass props in
// React will pass props in automatically but this just makes it easier to read
constructor(props) {
// `this` points to `Foo` now that you have a constructor
// it will also make the state obj available to your custom methods
this.state = { a: 123 };
// inside of your constructor, bind your custom methods to `this`
// if you have more than one, bind them all here
this.clickHandler = this.clickHandler.bind(this)
}
clickHandler() {
this.setState({ a: 456 });
}
render() {
return (
<div>
<h1>Hello, world! {this.state.a} </h1>
<button onClick={this.clickHandler}>Click Me</button>
</div>
);
}
}
You can use ES6 arrow functions. They prevent you from having to call .bind(this) for every function.
clickHandler = () => {
this.setState({ a: 456 });
}
<button onClick={this.clickHandler}>Click Me</button>
I believe there's no way to automatically bind every function you have to bind, simply because you are calling another component whenever you use onClick which makes your this won't work anymore (e.g. you have used a button in your example).
However, there are two other ways, you can either bind it in the constructor (similar to what you suggested to bind it in componentDidMount() but that won't work), like this:
constructor( props ){
super( props );
this.clickHandler = this.clickHandler.bind(this);
}
Or you can either change your function to an arrow function if you do not want to use an arrow function in render method like this onClick={()=>clickHandler()}, which is no good because you'll create a new function instance every time render is called :
clickHandler = () => {
this.setState({ a: 456 });
}
<button onClick={this.clickHandler}>Click Me</button>
I personally recommend the second way because you don't have to write one more line for the binding. More importantly, you can pass extra params directly from the clickHandler like this:
clickHandler = (addMore, addEvenMore) => () => {
this.setState({ a: 456 + addMore + addEvenMore });
// set a to 456 + 100 + 200
}
<button onClick={this.clickHandler(100, 200)}>Click Me</button>
With a binding in constructor, you cannot pass parameters, you have to do the binding when you pass the function to button, making the line clumsy, because the handler now describe multiple actions (the onClick action and the bind action) with the existence of the word bind:
<button onClick={this.clickHandler.bind(this, 100, 200)}>Click Me</button>
You can bind in the constructor. However, if you want "auto binding", I'd recommend using arrow functions since they inherit the lexical scope of this -- where this refers to the parent class versus an unbinded callback method that loses its lexical scope and this refers to the window.
In addition, I'd avoid binding this in the callback function because React has to recreate the function for each re-render (which can lead to an ever so slightly slower performance).
That said, you could do something like the example below -- although I don't recommend it, since not all of these methods would need to be binded to this if they weren't used as a callback in the render method (also Object.getOwnPropertyNames is not supported in older browsers):
import React from "react";
import "./styles.css";
class App extends React.Component {
constructor() {
super();
this.state = { a: 123 };
Object.getOwnPropertyNames(App.prototype)
.filter(method => !["constructor", "render"].includes(method))
.forEach(method => {
this[method] = this[method].bind(this);
});
}
handleSetClick() {
this.setState({ a: 456 });
}
handleResetClick() {
this.setState({ a: 123 });
}
render() {
return (
<div>
<h1>Hello, world! {this.state.a} </h1>
<button type="button" onClick={this.handleSetClick}>
Click Me
</button>
<br />
<button type="button" onClick={this.handleResetClick}>
Reset
</button>
</div>
);
}
}
export default App;
Working example:
What it looks like to "auto" bind (compiled):
https://pastebin.com/dZE0Hdnn
What it looks like to use arrow functions (compiled):
https://pastebin.com/e0xmh1fn
The main difference is that arrow functions instantiate the class versus being bound as a prototype to the class when bound in the constructor. This mostly affects inheritance, which you can read more about here. That said, React components don't usually extend from plain classes, instead they either extend from React's Component or PureComponent, and you won't be directly calling a Class.prototype, so take the article with a grain of salt (also, the article is very old and the performance numbers are outdated).
On a side note, you also bind using decorators, although support for decorators is hit or miss (since they're still in proposal stage -- or were, I haven't checked in awhile).

Which object owns react click handler code?

I know that when using React class methods arrow functions are a great way to lock in this. For example I might have a click handler:
clickHandler = () => {
// some code using 'this'
// eg this.state
}
// ... and in the render method
<button onClick={() => this.clickHandler()}>Test Button</button>
However if I were to use a non-arrow function syntax what object owns the code? That is, what is this?
I have tried the following but Typescript will not compile:
clickHandler = function() {
console.log(this); // also tried to coerce this as any type
}
// Error: 'this' implicitly has type 'any' because it does not have a type annotation.ts(2683)
It depends on how you call the function and whether or not you bind it.
class Test extends React.Component {
clickHandler = function() {
console.log(this);
}
render() {
return (
<div>
<button onClick={this.clickHandler}>Option A</button>
<button onClick={this.clickHandler.bind(this)}>Option B</button>
<button onClick={() => this.clickHandler()}>Option C</button>
</div>
);
}
}
With the Option A button, the click handler is passed directly to the <button /> element. Since React assumes you bind this and won't do it for you, the this inside clickHandler will be undefined.
With the Option B button we're explicitly binding this.clickHandler to this, in which case the this inside clickHandler will refer to that specific instance of the Test component.
For Option C (which is what you're doing in your question) we are not setting this.clickHandler as the onClick handler, but we're defining a new arrow function that calls this.clickHandler. In this case, the new arrow function will automatically get the Test component as this and that one is passed along to clickHandler.
Note that the Option A version will allow components to explicitly bind the handler:
class Button extends React.Component {
render() {
return (
<button
onClick={this.props.onClick.bind(this)}
children={this.props.children}
/>
);
}
}
class Test extends React.Component {
clickHandler = function() {
console.log(this);
}
render() {
return <Button onClick={this.clickHandler}>Click</Button>;
}
}
In this case, this within Test.clickHandler() will actually be a reference to the Button instance.
Your "this" will be 'undefined' because React calls your function behind the scenes and it doesn't call it from the object instance (I.E MyComponent.onClickHandler(e)) it calls it like this (onClickHandler(e))
A simplified model of what's happening without React involved looks something like this.....
class FakeReactComponent {
myName() {
console.log(this);
}
}
// this is what you give a onClick prop on an element.
const functionPassedToOnClick= new FakeReactComponent().myName;
console.log(
functionPassedToOnClick() // this is how react calls it (this is undefined)
)
On method to get around this is to bind "this" of the function in the constructor of the component I.E
constructor(props: IProps) {
super(props);
this.onClickHandler = this.onClickHandler.bind(this);
}
This is actually the 'best practice' way to define all functions within a class for React Components as arrow functions don't go on the classes prototype and therefore fresh functions are created for every new React instance of that component; however with non-arrow functions each instance goes on the prototype and therefore reused for each react component instance.
Tricks like autobind are also not best practice because binding every function's this is unneccessary because only functions being called by React need to have their this bound and 99% of the time that's only functions being used as event handlers.

React passing parameter with arrow function in child component

I have these parent and child component, I want to pass click function to select an item in child component. Yet it seems the function in child component become automatically called instead of waiting until the user click the element. To make it clearer here is my parent and child components
export class ParentView extends Component {
state = {
selectedItem: {}
}
handleClick = (item) => {
alert('you click me');
this.setState({selectedItem: item});
}
render() {
let item = { name: 'Item-1' };
return (
<div>
<ChildItem item={item} handleClick={this.handleClick} />
</div>
);
}
}
export class ChildItem extends Component {
render() {
const {item, handleClick} = this.props;
return (
<div>
<a onClick={handleClick(item)} />
</div>
);
}
}
Those are my components using arrow function to pass handleClick to child component, yet alert always being called at first render without being triggered by user. Any suggestion?
You should pass a function itself to onClick, not a result of the passed function invocation.
If you would like to invoke it with param, you have options:
bind it with item with handleClick.bind(this, item). bind creates a new function will have a predefined first parameter - item
pass new arrow function like () => handleClick(item)
An example below:
export class ChildItem extends Component {
render() {
const { item, handleClick } = this.props;
return (
<div>
<a onClick={() => handleClick(item)} />
</div>
)
}
}
In your code you're invoking a function in onClick declaration, so the result of handleClick execution will be passed to onClick, what is most likely not something you wanted to achieve.
<a onClick={handleClick(item)} />
Update:
as #dhilt wrote, there is a drawback of such approach. Since the newly created arrow function and .bind also creates new function every time the render method of ChildItem is invoked, react will threat the resulted react element as a different, comparing to the previous "cached" result of render method, that means that likely it might lead to some performance problems in the future, there is even a rule regarding this problem for eslint, but you shouldn't just follow this rule because of two points.
1) performance problems should be measured. we don't forbid using Array.prototype.forEach in favor of a regular for because for is the same or "faster".
2) definition of click handlers as class properties leads to increasing of the initializing step of the component instance. Re-render is fast and efficient in react, so sometimes the initial rendering is more important.
Just use what's better for you and likely read articles like this https://cdb.reacttraining.com/react-inline-functions-and-performance-bdff784f5578
Accepted answer has a performance hit: ChildItem component will be re-rendered even if data hasn’t changed because each render allocates a new function (it is so because of .bind; same with arrow functions). In this particular case it is very easy to avoid such a problem by getting handler and its argument right from the props on new public class field:
export class ChildItem extends Component {
onClick = () => {
this.props.handleClick(this.props.item);
}
render() {
return (
<div>
<a onClick={this.onClick} />
</div>
);
}
}
ParentView remains untouched.
The ES6 way:
Using arrow functions =>
onClick={() => handleClick(item)}
(#havenchyk's answer is the ES5 way).

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

I am trying to refactor the following code from my render view:
<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange.bind(this,false)} >Retour</Button>
to a version where the bind is within the constructor. The reason for that is that bind in the render view will give me performance issues, especially on low end mobile phones.
I have created the following code, but I am constantly getting the following errors (lots of them). It looks like the app gets in a loop:
Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.
Below is the code I use:
var React = require('react');
var ButtonGroup = require('react-bootstrap/lib/ButtonGroup');
var Button = require('react-bootstrap/lib/Button');
var Form = require('react-bootstrap/lib/Form');
var FormGroup = require('react-bootstrap/lib/FormGroup');
var Well = require('react-bootstrap/lib/Well');
export default class Search extends React.Component {
constructor() {
super();
this.state = {
singleJourney: false
};
this.handleButtonChange = this.handleButtonChange.bind(this);
}
handleButtonChange(value) {
this.setState({
singleJourney: value
});
}
render() {
return (
<Form>
<Well style={wellStyle}>
<FormGroup className="text-center">
<ButtonGroup>
<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange(false)} >Retour</Button>
<Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChange(true)} >Single Journey</Button>
</ButtonGroup>
</FormGroup>
</Well>
</Form>
);
}
}
module.exports = Search;
Looks like you're accidentally calling the handleButtonChange method in your render method, you probably want to do onClick={() => this.handleButtonChange(false)} instead.
If you don't want to create a lambda in the onClick handler, I think you'll need to have two bound methods, one for each parameter.
In the constructor:
this.handleButtonChangeRetour = this.handleButtonChange.bind(this, true);
this.handleButtonChangeSingle = this.handleButtonChange.bind(this, false);
And in the render method:
<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChangeSingle} >Retour</Button>
<Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChangeRetour}>Single Journey</Button>
I am giving a generic example for better understanding, In the following code
render(){
return(
<div>
<h3>Simple Counter</h3>
<Counter
value={this.props.counter}
onIncrement={this.props.increment()} <------ calling the function
onDecrement={this.props.decrement()} <-----------
onIncrementAsync={this.props.incrementAsync()} />
</div>
)
}
When supplying props I am calling the function directly, this wold have a infinite loop execution and would give you that error, Remove the function call everything works normally.
render(){
return(
<div>
<h3>Simple Counter</h3>
<Counter
value={this.props.counter}
onIncrement={this.props.increment} <------ function call removed
onDecrement={this.props.decrement} <-----------
onIncrementAsync={this.props.incrementAsync} />
</div>
)
}
That usually happens when you call
onClick={this.handleButton()} - notice the () instead of:
onClick={this.handleButton} - notice here we are not calling the function when we initialize it
THE PROBLEM is here: onClick={this.handleButtonChange(false)}
When you pass this.handleButtonChange(false) to onClick, you are actually calling the function with value = false and setting onClick to the function's return value, which is undefined. Also, calling this.handleButtonChange(false) then calls this.setState() which triggers a re-render, resulting in an infinite render loop.
THE SOLUTION is to pass the function in a lambda: onClick={() => this.handleButtonChange(false)}. Here you are setting onClick to equal a function that will call handleButtonChange(false) when the button is clicked.
The below example may help:
function handleButtonChange(value){
console.log("State updated!")
}
console.log(handleButtonChange(false))
//output: State updated!
//output: undefined
console.log(() => handleButtonChange(false))
//output: ()=>{handleButtonChange(false);}
If you are trying to add arguments to a handler in recompose, make sure that you're defining your arguments correctly in the handler. It is essentially a curried function, so you want to be sure to require the correct number of arguments. This page has a good example of using arguments with handlers.
Example (from the link):
withHandlers({
handleClick: props => (value1, value2) => event => {
console.log(event)
alert(value1 + ' was clicked!')
props.doSomething(value2)
},
})
for your child HOC and in the parent
class MyComponent extends Component {
static propTypes = {
handleClick: PropTypes.func,
}
render () {
const {handleClick} = this.props
return (
<div onClick={handleClick(value1, value2)} />
)
}
}
this avoids writing an anonymous function out of your handler to patch fix the problem with not supplying enough parameter names on your handler.
The problem is certainly the this binding while rending the button with onClick handler. The solution is to use arrow function while calling action handler while rendering. Like this:
onClick={ () => this.handleButtonChange(false) }
From react docs Passing arguments to event handlers
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
This same warning will be emitted on any state changes done in a render() call.
An example of a tricky to find case:
When rendering a multi-select GUI component based on state data, if state has nothing to display, a call to resetOptions() is considered state change for that component.
The obvious fix is to do resetOptions() in componentDidUpdate() instead of render().
I got the same error when I was calling
this.handleClick = this.handleClick.bind(this);
in my constructor when handleClick didn't exist
(I had erased it and had accidentally left the "this" binding statement in my constructor).
Solution = remove the "this" binding statement.
The onClick function must pass through a function that returns the handleButtonChange() method. Otherwise it will run automatically, ending up with the error/warning. Use the below to solve the issue.
onClick={() => this.handleButtonChange(false)}
The solution that I use to open Popover for components is reactstrap (React Bootstrap 4 components).
class Settings extends Component {
constructor(props) {
super(props);
this.state = {
popoversOpen: [] // array open popovers
}
}
// toggle my popovers
togglePopoverHelp = (selected) => (e) => {
const index = this.state.popoversOpen.indexOf(selected);
if (index < 0) {
this.state.popoversOpen.push(selected);
} else {
this.state.popoversOpen.splice(index, 1);
}
this.setState({ popoversOpen: [...this.state.popoversOpen] });
}
render() {
<div id="settings">
<button id="PopoverTimer" onClick={this.togglePopoverHelp(1)} className="btn btn-outline-danger" type="button">?</button>
<Popover placement="left" isOpen={this.state.popoversOpen.includes(1)} target="PopoverTimer" toggle={this.togglePopoverHelp(1)}>
<PopoverHeader>Header popover</PopoverHeader>
<PopoverBody>Description popover</PopoverBody>
</Popover>
<button id="popoverRefresh" onClick={this.togglePopoverHelp(2)} className="btn btn-outline-danger" type="button">?</button>
<Popover placement="left" isOpen={this.state.popoversOpen.includes(2)} target="popoverRefresh" toggle={this.togglePopoverHelp(2)}>
<PopoverHeader>Header popover 2</PopoverHeader>
<PopoverBody>Description popover2</PopoverBody>
</Popover>
</div>
}
}

how do I pass data upwards in reactjs?

Say I have an app with some path app -> taskbar -> button -> modal -> textfield. I want the textfield to be some setting a user inputs and is used elsewhere in the app, maybe app -> differentButton -> differentModal displays this user setting for example
I'm brand new to react, but it seems data can only go downwards through props, right? Is it expected that I store this state externally in a db? I don't mind doing that, but it seems like there should be an easy way to do this that I'm overlooking?
You can store the state in the parent component and pass not only the value, but also the function that modifies the value to the child. Eg:
const App = React.createClass({
getInitialState () {
return {
name: 'Dave'
};
},
render () {
return (
<div>
<MyComponent name={this.state.name} changeName={this.onChangeName} />
</div>
)
},
onChangeName (name) {
this.setState({ name });
}
});
const MyComponent = React.createClass({
propTypes: {
name: React.PropTypes.string,
changeName: React.PropTypes.func.isRequired
},
render () {
return (
<div>
<input value={this.props.name} onChange={this.props.changeName} />
</div>
);
}
});
The canonical way would be to pass a callback function from a component which is higher up in the view hierarchy through props.
That higher ordered component would encapsulate the state that you wish to modify, triggering a re-render of the sub-tree.
In your case, it looks like you would have to use App as the shared parent component for sharing state. So in App, you'd probably have a function such as:
handleTextInput: function(text) {
// handle the text input here (set some state, make an ajax call, etc)
},
And App's render function might look like this:
render: function() {
return (
<TaskBar onTextSubmit={this.handleTextInput} />
);
}
In your TaskBar component, you'd pass the callback down to Button, and so on.
Finally, in your modal component, you'd have a render function like:
render: function() {
return (
<form onSubmit={this.props.onTextSubmit}>
...
</form>
);
}
Of course, this is can quickly get quite clumsy if you have a deeply nested hierarchy, so a better approach would be to use a library for state management such as Redux.

Resources