Function call in react native - javascript

I am trying to call a function inside a class but confused with below syntax.
Why I need to use bind method when calling a function?
Why arrow function is not getting executed?
import React, { Component } from 'react'
import { Text, View } from 'react-native'
//arrow function not getting executed!
myFun = data => {
console.warn(data);
}
myFun(data){
console.warn(data);
}
class Hello extends Component {
render() {
return (
<View>
{this.myFun("first")}
{this.myFun.bind(this, "second")}
</View>
);
}
}
export default Hello;
Note: I have removed comment from the first method!

Functions should be called inside class to get them available with this context.
import React, { Component } from 'react'
import { Text, View } from 'react-native'
class Hello extends Component {
constructor(props) {
super(props);
}
//both normal fun and arrow fun should be inside class to get it executed!
myFun1 = data => {
console.warn(data);
}
myFun2(data){
console.warn(data);
}
render() {
return (
<View>
{this.myFun("first")}
{this.myFun2.bind(this, "second")}
</View>
);
}
}
export default Hello;
When you are using this.myfun2.bind(this ) then you are adding it to current context of **this **. Basically after then only you will be able to do this.state , this.props, this.setstate etc
Also bind function returns a bounded function that, when executed later, the function will have the correct context ("this") for calling the original function. So bind function can be used when the function needs to be called later in certain events when it's useful.

Put the function into the class
Bind the function in the constructor:
this.handleChange = this.handleChange.bind(this);
The bind method doesn't execute the function/method, only it return the function with new context (this)

The keyword this retains the value of the enclosing lexical context in our case the Hello class. As you can see in your example this which means Hello doesn't have myFun & yet you're trying to call that function!
So either you put the function inside the class or you change your call method to myFun("first") shortly.
Lastly, if you need to use this keyword inside your function, then you'll have to use the bind(this) method.

you need to call the function as below.
import React, { Component } from 'react'
import { Text, View } from 'react-native'
myFun = data => {
console.warn(data);
}
class Hello extends Component {
render() {
return (
<View>
{()=>this.myFun("first")}
</View>
);
}
}
export default Hello;

Related

React onClick, Cannot read property 'bind' of undefined

I'm trying to run a onclick function in react
My button:
<button onClick={this.logOut.bind(this)}>LogOut</button>
My function
function logOut(){
Auth.signOut()
.then(data => console.log(logout)
.catch(err => console.log(err));
}
but the an error comes back Cannot read property 'bind' of undefined
Firstly, never bind in your render method. bind returns a new method each time you call it, which means that react cant optimise your render method. React looks at the props of components to see if anything has changed, and with functions, it compares equality by object reference. Since your function will be a new function each time, react will think things are changing.
Secondly, you can use an arrow function in your component to avoid the need for bind all together.
Here are two ways you can write this differently, first with bind:
class MyComponent extends Component {
constructor() {
this.logOut = this.logOut.bind(this);
}
function logOut() {
//...
}
function render() {
return <button onClick={this.logOut}>LogOut</button>
}
}
Secondly with an arrow function:
class MyComponent extends Component {
logOut = () => {
//...
}
function render() {
return <button onClick={this.logOut}>LogOut</button>
}
}
Would be helpful if you can please give more details .
Just tried an example in codepen and I see it working fine.
https://codepen.io/anon/pen/qKBdaB?editors=0011
class Toggle extends React.Component {
handleClick() {
console.log('Hello')
}
render() {
return (
<button onClick={this.handleClick.bind(this)}>
SayHello
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);

React - Setting component state using a function outside of state, is it wrong?

Is it wrong to use setState in a function outside of the React component?
Example:
// myFunction.js
function myFunction() {
...
this.setState({ ... })
}
// App.js
import myFunction from './myFunction
class App extends Component {
constructor() {
super()
this.myFunction = myFunction.bind(this)
}
...
}
I'm not sure the way you're binding will actually work. You could do something like:
export const getName = (klass) => {
klass.setState({ name: 'Colin'})
}
then
class App extends Component {
state = {
name: 'React'
};
handleClick = () => {
getName(this);
}
render() {
return (
<div>
<p>{this.state.name}</p>
<button onClick={this.handleClick}>change name</button>
</div>
);
}
}
Working example here.
So the only reasons to do this is if you are reducing repeated code, e.g. two components use the same logic before calling this.setState, or if you want to make testing easier by having a separate pure function to test. For this reason I recommend not calling this.setState in your outside function, but rather returning the object you need so it can you can call this.setState on it.
function calculateSomeState(data) {
// ...
return { updated: data };
}
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.state = calculateSomeState(props.data);
}
handleChange = (e) => {
const value = e.target.value;
this.setState(calculateSomeState({ ...props.data, value }));
}
}
It looks like a bug waiting to happen... If you want to use an external function to set state, you can use the alternative syntax provided by React:
this.setState((prevState, props) => {
return updatedState; //can be a partial state, like in the regular setState
});
That callback can easily be extracted to an external function and it's guaranteed to work
It is not wrong, the function is never called outside the component. This is a mix-in technique. bind isn't needed, as long as the function isn't used as a callback. In this case myFunction is same among all instances, a more efficient way would be:
class App extends Component {}
App.prototype.myFunction = myFunction;

Calling a function in React

I'm a beginner in React, and I'm a little confused about calling a function in React.
I saw the following ways and I don't know when to use each and which one.
handleAddTodo ={this.handleAddTodo}
handleAddTodo ={this.handleAddTodo()}
handleAddTodo ={handleAddTodo}
handleAddTodo ={this.handleAddTodo}
handleAddTodo ={handleAddTodo()}
Are these interchangeable? Could I do that to handle an event, the same way to call a function?
Are these interchangeable?
Short answer: No.
Let's take a look at the different snippets you've posted:
someFunction() vs someFunction
With the former syntax, you are actually invoking that function. The latter is just a reference to that function. So when do we use which?
You would use someFunction() when you want that function invoked and its result returned immediately. In React, this is typically seen when you split parts of your JSX code to a separate function; either for reasons of readability or reusability. For example:
render() {
myFunction() {
return <p>Foo Bar</p>;
}
return (
<div>
{myFunction()}
</div>
);
}
You would use someFunction when you want only to pass the reference to that function to something else. In React, this is usually an event handler that is passed down to another child-component via props so that that component can call the event handler when it needs to. For example:
class myApp extends React.Component {
doSomething() {
console.log("button clicked!");
}
render() {
return (
<div>
<Button someFunction={this.doSomething} />
</div>
);
}
}
class Button extends React.Component {
render() {
return (
<button onClick={this.props.someFunction}>Click me</button>
);
}
}
someFunction() vs this.someFunction()
This has to do with the context of the function. Basically, "where is this function?". Is part of the current Component, then use this.someFunction(), is it part of the parent Component passed in as props, then use this.props.someFunction(). Is it a function inside the current method, then just use someFunction().
Obviously, there's a lot more to it than that, but it's the best basic summary I can give.
For a better understanding, have a read here. It is a great guide to how the this keyword works in Javascript and in React in particular.
If you want to call a function options 2 and with some assumptions 5 should work.
If you want to actually pass a function as a property to some child component so that it could call it later (say to notify your root element on some event) then option 1 (with prebind) and 3 (with defining a variable const {handleAddTodo} = this and prebind :) ) should work
// this works if handleAddTodo was prebinded or doesn't use this
handleAddTodo ={this.handleAddTodo}
// this probably wont work unless handleAddTodo is higher order function that returns another function
handleAddTodo ={this.handleAddTodo()}
// This wont work unless you have a var/let/const that is referencing a function
handleAddTodo ={handleAddTodo}
// Same as 1
handleAddTodo ={this.handleAddTodo}
// 3 and 2 combined
handleAddTodo ={handleAddTodo()}
To call the function you have to add ()
{this.handleAddTodo()}
About handling events - Handling#Events
Arrow Functions - Functions#ArrowFunctions
In ES6 you can use normal function or Arrow Function:
Function1 (Normal Function)
functionA(){
//Something here
}
Then should call this.functionA()
Function2 (ArrowFunction)
functionA = () => {
//SomeThing Here
}
Then should call this.functionA
*Function3 (Eg: in a const of React) *
const A = (functionTest) =>{
return (
<div>{functionTest}</div>
);
}
functionTest is mapStateToProps in React :)
I hope it is helpful for you :)
this is correct -> handleAddTodo ={this.handleAddTodo}
When function passing to child component you have to bind your function like this handleAddTodo ={this.handleAddTodo.bind(this)}. below code help out your doubt.
Simple Example
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 'Initial data...'
}
this.updateState = this.updateState.bind(this);
};
updateState() {
this.setState({data: 'Data updated...'})
}
render() {
return (
<div>
<button onClick = {this.updateState}>CLICK</button>
<h4>{this.state.data}</h4>
</div>
);
}
}
export default App;
Child Events
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 'Initial data...'
}
this.updateState = this.updateState.bind(this);
};
updateState() {
this.setState({data: 'Data updated from the child component...'})
}
render() {
return (
<div>
<Content myDataProp = {this.state.data}
updateStateProp = {this.updateState}></Content>
</div>
);
}
}
class Content extends React.Component {
render() {
return (
<div>
<button onClick = {this.props.updateStateProp.bind(this)}>CLICK</button>
<h3>{this.props.myDataProp}</h3>
</div>
);
}
}
export default App;
Refer here
You can trigger events with this.props.someProps(). Check the following sample.
import React, { Component } from 'react';
class AddToDo extends Component {
render() {
return (
<button onClick={ev => this.props.handleAddToDo(ev, 'hello')}>
{this.props.title}
</button>
)
}
}
class Todos extends Component {
handleAddToDo(ev, someVal) {
// do something
}
render() {
return (
<AddToDo title="Add" handleAddToDo={(ev, someVal) => this.handleAddToDo(ev, someVal)} />
)
}
}
export default Todos;

React unit tests with Enzyme don't re-bind context of helper functions

This is an interesting issue that I came across while trying to refactor some of my React components using AirBnB's React testing library, Enzyme.
I think the best way to explain my problem is through an example.
Here is a small React component that will display a message depending on the props it receives from its parent component:
test.js:
import React from 'react';
function renderInnerSpan() {
const {foo} = this.props;
if (foo) {
return <span>Foo is truthy!</span>;
}
return <span>Foo is falsy!</span>;
}
export default class extends React.Component {
render() {
return (
<div>
{renderInnerSpan.call(this)}
</div>
);
}
}
And here is a test suite for this component with two passing tests:
test.spec.js:
import Test from '../../src/test';
import React from 'react';
import {shallow} from 'enzyme';
import {expect} from 'chai';
describe('Test Suite', () => {
let renderedElement,
expectedProps;
function renderComponent() {
const componentElement = React.createElement(Test, expectedProps);
renderedElement = shallow(componentElement);
}
beforeEach(() => {
expectedProps = {
foo: true
};
renderComponent();
});
it('should display the correct message for truthy values', () => {
const span = renderedElement.props().children;
expect(span.props.children).to.equal('Foo is truthy!');
});
it('should display the correct message for falsy values', () => {
expectedProps.foo = false;
renderComponent();
const span = renderedElement.props().children;
expect(span.props.children).to.equal('Foo is falsy!');
});
});
This works fine, but the Test component's current implementation isn't as efficient as it could be. By using .call(this), it is creating a new function every time the render() function is called. I could avoid this by binding the correct context of this in the component's constructor, like so:
export default class extends React.Component {
constructor(props) {
super(props);
renderInnerSpan = renderInnerSpan.bind(this);
}
render() {
return (
<div>
{renderInnerSpan()}
</div>
);
}
}
After this change, the component still works as intended, but the tests start failing:
AssertionError: expected 'Foo is truthy!' to equal 'Foo is falsy!'
Expected :Foo is falsy!
Actual :Foo is truthy!
I added a console.log(props.foo) in the constructor, which confirmed that the constructor was still being called when I expected it to, and the props it's receiving are correct. However, I added a console.log(foo) inside of renderInnerSpan, and it looks like the value is true all the time, even after re-rendering the component with its foo prop explicitly set to false.
It looks like renderInnerSpan is only be bound once, and Enzyme is re-using this for every single test. So, what gives? I'm re-creating my component in the test, which is calling its constructor with the values I expect - why is my bound renderInnerSpan function continuing to use old values?
Thanks in advance for the help.
The issue here is that a function cannot be bound multiple times, as you are trying to in your test case.
The reason for that is that the context is not simply a property of the function itself. When a function is bound, it is rather wrapped in a bound function exotic object.
The context (this-assignment) is saved in the [[BoundThis]] property of the exotic object. The bound function will always be called with this context, even if it is bound again.
You can test this yourself:
function foo() {
console.log(this.bar);
}
foo(); // undefined
foo = foo.bind({bar: 1});
foo(); // 1
foo = foo.bind({bar: 2});
foo(); // 1
To solve this issue, I suggest you remove the dependency to the context from the rendering function and transfer all required input via function parameters instead:
function renderInnerSpan(foo) {
if (foo) {
return <span>Foo is truthy!</span>;
}
return <span>Foo is falsy!</span>;
}
export default class extends React.Component {
render() {
return (
<div>
{renderInnerSpan(this.props.foo)}
</div>
);
}
}
This removes a hidden dependency and makes the code more readable and maintainable. If you ever decide to move the rendering function to its own module, you can now easily do so.
Since you do not need to bind the function context in the constructor anymore, you can even transform your React component into a stateless function:
import renderInnerSpan from './renderInnerSpan'
export default (props) => (
<div>
{renderInnerSpan(props.foo)}
</div>
);
So much nicer and more readable! :-)
It looks to me that you defined the renderInnerSpan function outside your class and that might create some problems.
Try this:
import React from 'react';
export default class extends React.Component {
render() {
return (
<div>
{this.renderInnerSpan.bind(this)}
</div>
);
}
renderInnerSpan() {
const {foo} = this.props;
if (foo) {
return <span>Foo is truthy!</span>;
}
return <span>Foo is falsy!</span>;
}
}
Another thing is that your renderComponent function could be rewritten like this:
function renderComponent(expectedProps) {
const componentElement = React.createElement(Test, expectedProps);
return shallow(componentElement);
}
And if you are changing the props in each test, then there is no reason to set the props in a beforeEach block. Just use the new renderComponent in each test instead.
it('should display the correct message for truthy values', () => {
renderedElement = renderComponent({foo: true});
const span = renderedElement.props().children;
expect(span.props.children).to.equal('Foo is truthy!');
});

React Store is returning null for value of `this`

I'm running into an issue where this is returning null in my store for my React component. I believe I need to bind this, but I am unsure. I'm also using React Router and have my component set up in a wrapper so I'm able to pass props to it. Any help is appreciated!
COMPONENT
import React from 'react';
import PaymentStore from './../store/paymentStore';
class InitialPaymentScreen extends React.Component {
constructor(props) {
super(props)
}
render() {
console.log(this.props)
return (
<div className="payment-form-submit" onClick={this.props.store.init}>Next</div>
);
}
}
class PaymentForm extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<section className="main-content payment-form-wrapper">
<InitialPaymentScreen store={this.props.store}/>
</section>
);
}
}
export default class PaymentFormWrapper extends React.Component {
render() {
return (
<PaymentForm store={PaymentStore} mode="foo"/>
);
}
}
STORE
let PaymentStore = {
handleClickNext() {
console.log("hello")
},
init() {
console.log(this) // returns null
this.handleClickNext(); // cannot read property of null
},
};
export default PaymentStore;
Looks like you need to bind it indeed. You can do that by changing
<div className="payment-form-submit" onClick={this.props.store.init}>Next</div>
to
<div className="payment-form-submit" onClick={this.props.store.init.bind(this.props.store)}>Next</div>
# or
var init = this.props.store.init.bind(this.props.store);
<div className="payment-form-submit" onClick={init}>Next</div>
Alternatively, if InitialPaymentScreen only needs init from store, the binding could happen in PaymentForm, and InitialPaymentScreen could only receive the function.
The binding needs to be done because javascript is, well, unique in some ways.
Generally, a function's this is bound to literally what's it being called from. In your case, store.init() means the init function has this as store.
Now, if you assign store.init to a variable and call that, it doesn't know what's this! (this is probably the most common issue for people learning JS) — because during invocations, it tries to infer this by seeing which object that function is stored in.
To get make the function know what's its context then, you have two options basically:
a. fn.bind(something), which returns a bound function, or
b. create an anonymous function which invokes that one

Categories

Resources