React - How do you call a function from inside another function - javascript

Suppose I had this layout below:
class Navigation extends React.Component {
primaryFun() { console.log('funn') }
secondaryFun() {
this.primaryFun();
}
}
I'd of expected this to then call primary but instead I get an undefined, Ok.
So I thought I'd add a constructor to bind the function to this:
constructor(props) {
super(props)
this.primaryFun = this.primaryFun.bind(this);
}
but primary fun is still undefined.
In my real project I'm calling these on a mouseOut event.
Feels like the above should work and tbh the documentation for React is all over the shot so couldn't find much here.

Are you looking for something like this calling one function inside the other
import React, { Component } from 'react';
import './App.css'
class App extends Component {
constructor(){
super()
this.mouseClick = this.mouseClick.bind(this);
this.primaryFun = this.primaryFun.bind(this);
this.secondaryFun = this.secondaryFun.bind(this);
}
primaryFun(){
console.log('primaryFun funn')
}
secondaryFun(){
console.log('secondaryFun funn')
this.primaryFun()
}
mouseClick(){
this.secondaryFun()
}
render() {
return (
<div onClick={this.mouseClick}>
Hello World!
</div>
);
}
}
export default App;
Here when you click on "Hello world" secondaryFun is called and inside secondaryFun , primaryFun is been triggered

You also need to bind the secondaryFun function to use this inside that. Without that, the this inside the function secondaryFun will refers to the function scope which is secondaryFun

You need to bind this in your mouseOut
onMouseOut={this.secondaryFun.bind(this)}
Or a as best practice use the Lambda syntax. It'll bind this for you
onMouseOut={()=>this.secondaryFun()}

Make sure both functions have the correct this scope. If you are using class properties, see https://babeljs.io/docs/plugins/transform-class-properties/. Which already present on the babel-preset-react-app used by create-react-app, you can use that and write those as arrow functions, as seen on the babel link. And avoid having to use .bind on the constructor.

You must bind() both two functions.
You should that:
class Navigation extends React.Component {
constructor(props) {
super(props)
this.primaryFun = this.primaryFun.bind(this);
this.secondaryFun = this.secondaryFun.bind(this);
}
primaryFun() {
console.log('funn')
}
secondaryFun() {
this.primaryFun();
}
}

Related

npm debounce failing in ReactJS

Using npm debounce I get an error with the following code in ReactJS. The error
Javascript - Uncaught TypeError: Object(...) is not a function
happens when the function is passed into debounce()
import React, { Component } from 'react';
import { debounce } from 'debounce';
class test extends Component {
constructor(props) {
super(props);
this.state = {
yolo: {}
};
}
foobar(param) {
debounce(() => {
this.setState({yolo: param});
}, 99);
}
render () {
return (
...
<SomeComponent action={this.foobar.bind(this)} />
...
);
}
}
I have tried some of the solutions mentioned in Perform debounce in React.js
but none seem to work.
import React, { Component } from 'react';
import debounce from 'debounce';
class test extends Component {
constructor(props) {
super(props);
this.state = {
yolo: {}
};
this.foobar.bind(this);
}
foobar(param) {
debounce(() => {
this.setState({yolo: param});
}, 99);
}
render () {
return (
...
<SomeComponent action={this.foobar.bind(this)} />
...
);
}
}
The top set of code should work. Ok, so the reason why your call to foobar was not working before was because you were missing this line: this.foobar.bind(this);. Your previous syntax worked just fine and is actually preferable to the this.foobar =. Reason being because one is ES6 syntax and the other is ES5. What that bind function does when you call it is attach a particular this context for when the function is called. Here is a reference to an article that explains that: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Now the second part of this was the import. when you use the object bracket syntax, thats actually called object destructuring. So what that does is whatever that object exports it tries to access a debounce property and make that accessible in the current file. Problem is I suspect that that npm package is already export a function as its default so you don't need to access something on it. Make sense?
Hope this all helps! Best of luck (thumbsup)

Reactjs ES6 Access function outside of class

I have a class "MessageDisplay" of which I want to call the function sendMassageToServer from the outside. I´ve built a helper function to call from another file. But how do you export functions that are inside classes?
These data are just examples.
main.js
export function sendSpeechToServer(query){
MessageDisplay.sendMessageToServer(query);
}
class MessageDisplay extends React.Component {
constructor(props) {
super(props);
this.state = {message : []};
}
(export const??) sendMessageToServer(searchQuery) {
...code
}
}
We are accesing the sendSpeechToServer() function from another file. Unortunately I am not even able to reach sendMessageToServer() from inside sendSpeechToServer().
Any help surely is appreciated. :)
EDIT:
The answer is found. For any other people:
export function sendSpeechToServer(query){
let test = new MessageDisplay();
test.sendMessageToServer(query);
}
Better way to separate component(MessageDisplay) and sendMessageToServer.
Then you can import sendMessageToServer awry where. You can inject sendMessageToServer like a props:
// main.js
import { sendMessageToServer } from './api';
<MessageDisplay sendMessage={sendMessageToServer} />
// MessageDisplay.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class MessageDisplay extends Component {
static propTypes = {
sendMessage: PropTypes.func.isRequired,
}
handleClick = (e) => {
e.preventDefault();
this.props.sendMessage();
};
render() {
return (<button onClick={this.handleClick}>Send to</button>)
}
}
export default MessageDisplay;
It useful for testing.
Instantiating a component manually for general purposes like let test = new MessageDisplay() is an antipattern, this indicates that a class is misused.
React component classes are primarily intended to make lifecycle hooks available and maintain state. They can sparsely benefit from inheritance (besides the relationship with React.Component) and other OOP traits.
The fact that it's possible to use component method as new MessageDisplay().sendMessageToServer(query) means that it was a mistake to make it component method in the first place. Classes aren't supposed to be glorified namespaces; ES modules play the role of namespaces in modern JavaScript.
A proper way is to extract the method and use it in both places as regular helper function. Functional approach is considered idiomatic in React.
export function sendSpeechToServer(query){
let test = new MessageDisplay();
test.sendMessageToServer(query);
}
it is bad, because you should not, create new react.component instance with new keyword,
better use static function like this
static sendMessageToServer(searchQuery) {
...code
}
and then
export function sendSpeechToServer(query){
MessageDisplay.sendMessageToServer(query);
}

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;

how come class methods don't behave normally with react components?

Given a component like this :
class App extends Component {
state = {}
sayHello() {
// 'this' is undefined here... It should point to the component instance
}
render() {
return (
<div onClick={this.sayHello}>
clickMe
</div>
);
}
}
how come sayHello can't access this ? That is not the expected behavior of an ES6 class.
What am I missing out on ?
In javascript this depends on how you call the method. This can be changed by binding this inside a method. To illustrate what is happening in your example:
class App {
sayHello() {
console.log(this)
}
}
const a = new App()
a.sayHello() // A {}
const callback = a.sayHello // what you are passing as a callback to onClick
callback() // undefined
To fix this problem you need to bind this in sayHello function. You can use class properties to achieve this. This is still an experimental feature of javascript but seems to be a community accepted way of binding this for React components.
class App {
sayHello = () => {
console.log(this)
}
}
callback() // A {}
div it self is another Class so when calls your sayHello inside himself it will change this.
All you have to do is bind this to sayHello or call it via ES6 arrow function.
<div onClick={ this.sayHello.bind(this) }>
or
<div onClick={ (event) => this.sayHello(event) }>

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