Calling a function in React - javascript

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;

Related

Function call in react native

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;

Try to call function inside controller in react component

I am trying to get use to the base code of webtorrent desktop, here you can check the code of my branch:
https://github.com/refreex/webtorrent-desktop
It uses Node.js and Electron
The problem I am facing is I create a new controller called playlists-controller.js and there is a function called getAllPlaylists that I need to consume within a React component called playlists-list.js
I am trying to use the same concepts that were used before but I don't understand how can i call that function from my controller inside the react's component.
There is a file called main.js where here are listed all the functions that the controllers have like this one:
//Playlists
'createPlaylist': (name) => controllers.playlists().createPlaylist(name),
'addAlbumToPlaylist': (infoHash, files) => controllers.playlists().addAlbumToPlaylist(infoHash, files),
'addSongToPlaylist': (infoHash, file) => controllers.playlists().addSongToPlaylist(infoHash, file),
'getAllPlaylists': () => controllers.playlists().getAllPlaylists(),
Along the app there are a lots of calls using a dispatcher but also I think is mostly used for events but I am not sure.
So basically in the page playlists-list.js I need to call the function getAllPlaylists that is in playlists-controller.js
What is a good approach to do that?
Thanks in advance.
This can be done in two ways. One, passing the function as props to that component or we can export the getAllPlaylist method and use it by importing into the playlists-lists component. I hope this will help you solve your issue.
Method 1:
class PlaylistController extends React.Component {
getAllPlaylist = () => {
alert('Do Something Here As Per Your Requirement!')
}
render () {
return (
<container>
<PlaylistList sendFunction={this.getAllPlaylist} />
</container>
)
}
}
class PlaylistList extends React.Component {
render () {
return (
<div>
<button onClick={this.props.sendFunction}>Click Here To Call Playlist-list Function</button>
</div>
)
}
}
Method 2:
class PlaylistController extends React.Component {
export const getAllPlaylist = ()=>{
//do something as per the requirement
}
}
import {getAllPlaylist} from './playlistController'
class PlaylistList extends React.Component {
handleClick = () => {
getAllPlaylist();
}
render () {
return (
<div>
<button onClick={this.handleClick}>Click Here To Call Playlist-list Function</button>
</div>
)
}
}

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;

setState/use State in external function react

Considering this pseudocode:
component.js
...
import {someFunc} from "./common_functions.js"
export default class MyComp extends Component {
constructor(props) {
super(props);
this.someFunc = someFunc.bind(this);
this.state = {...};
}
_anotherFunc = () = > {
....
this.someFunc();
}
render() {
...
}
}
common_functions.js
export function someFunc() {
if(this.state.whatever) {...}
this.setState{...}
}
How would I bind the function someFunc() to the context of the Component? I use it in various Components, so it makes sense to collect them in one file. Right now, I get the error "Cannot read whatever of undefined". The context of this is unknown...
You can't setState outside of the component because it is component's local state. If you need to update state which is shared, create a store (redux store).
In your case, you can define someFunction at one place and pass it the specific state variable(s) or entire state. After you are done in someFunction, return the modified state and update it back in your component using setState.
export function someFunc(state) {
if(state.whatever) {...}
const newState = { ...state, newValue: whateverValue }
return newState
}
_anotherFunc = () = > {
....
const newState = this.someFunc(this.state);
this.setState({newValue: newState});
}
it's not a React practice and it may cause lot of problems/bugs, but js allows to do it:
Module A:
export function your_external_func(thisObj, name, val) {
thisObj.setSate((prevState) => { // prevState - previous state
// do something with prevState ...
const newState = { // new state object
someData: `This is updated data ${ val }`,
[name]: val,
};
return newState
});
}
Then use it in your react-app module:
import { your_external_func } from '.../your_file_with_functions';
class YourReactComponent extends React.Component {
constructor(props, context) {
super(props, context);
this.state={
someName: '',
someData: '',
};
}
handleChange = (e) => {
const { target } = event;
const { name } = target;
const value = target.type === 'checkbox' ? target.checked : target.value;
your_external_func(this, name, value);
}
render() {
return (<span>
{ this.state.someData }
<br />
<input
name='someName'
value={ this.state.someName }
onChange={ this.handleChange }
/>
</span>);
}
}
It's a stupid example :) just to show you how you can do it
The best would obviously to use some kind of external library that manages this. As others have suggested, Redux and MobX are good for this. Using a high-order component to wrap all your other components is also an option.
However, here's an alternative solution to the ones above:
You could use a standard javascript class (not a React component) and pass in this to the function that you are calling from that class.
It's rather simple. I've created a simple example below where the state is changed from a function of another class; take a look:
class MyApp extends React.Component {
constructor() {
super();
this.state = {number: 1};
}
double = () => {
Global.myFunc(this);
}
render() {
return (
<div>
<p>{this.state.number}</p>
<button onClick={this.double}>Double up!</button>
</div>
);
}
}
class Global {
static myFunc = (t) => {
t.setState({number: t.state.number*2});
}
}
ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"><div>
There is a functional form of setState that can even be used outside of a component.
This is possible since the signature of setState is:
* #param {object|function} partialState Next partial state or function to
* produce next partial state to be merged with current state.
* #param {?function} callback Called after state is updated.
See Dan's tweet: https://twitter.com/dan_abramov/status/824308413559668744
This all depends on what you are trying to achieve. At first glance I can see 2 options for you. One create a child component and two: use redux as redux offers a singular state between all of your child components.
First option:
export default class parentClass extends Component {
state = {
param1: "hello".
};
render() {
return (
<Child param1={this.state.param1}/>
);
}
}
class Child extends Component {
render() {
console.log(this.props.param1);
return (
<h1>{this.props.param1}</h1>
);
}
}
Now the above child component will have the props.param1 defined from the props passed from it's parent render function.
The above would work but I can see you're trying to establish a 'common' set of functions. Option 2 sort of provides a way of doing that by creating a singular state for your app/project.
If you've haven't used redux before it's pretty simple to use once you've got the hang of it. I'll skip out the setup for now http://redux.js.org/docs/basics/UsageWithReact.html.
Make a reducer like so:
import * as config from './config';//I like to make a config file so it's easier to dispatch my actions etc
//const config.state = {param1: null}
//const config.SOME_FUNC = "test/SOME_FUNC";
export default function reducer(state = config.state, action = {}) {
switch(action.type) {
case config.SOME_FUNC:
return Object.assign({}, state, {
param1: action.param1,
});
break;
default:
return state;
}
}
}
Add that to your reducers for your store.
Wrap all your components in the Provider.
ReactDOM.render(
<Provider store={store} key="provider">
<App>
</Provider>,
element
);
Now you'll be able to use redux connect on all of the child components of the provider!
Like so:
import React, {Component} from 'react';
import {connect} from 'react-redux';
#connect(
state => (state),
dispatch => ({
someFunc: (param1) => dispatch({type: config.SOME_FUNC, param1: param1}),
})
)
export default class Child extends Component {
eventFunction = (event) => {
//if you wanted to update the store with a value from an input
this.props.someFunc(event.target.value);
}
render() {
return (
<h1>{this.props.test.param1}</h1>
);
}
}
When you get used to redux check this out https://github.com/redux-saga/redux-saga. This is your end goal! Sagas are great! If you get stuck let me know!
Parent component example where you define your callback and manage a global state :
export default class Parent extends Component {
constructor() {
super();
this.state = {
applyGlobalCss: false,
};
}
toggleCss() {
this.setState({ applyGlobalCss: !this.state.applyGlobalCss });
}
render() {
return (
<Child css={this.state.applyGlobalCss} onToggle={this.toggleCss} />
);
}
}
and then in child component you can use the props and callback like :
export default class Child extends Component {
render() {
console.log(this.props.css);
return (
<div onClick={this.props.onToggle}>
</div>
);
}
}
Child.propTypes = {
onToggle: PropTypes.func,
css: PropTypes.bool,
};
Well for your example I can see you can do this in a simpler way rather than passing anything.
Since you want to update the value of the state you can just return it from the function itself.
Just make the function you are using in your component async and wait for the function to return a value and set the state to that value.
import React from "react"
class MyApp extends React.Component {
constructor() {
super();
this.state = {number: 1};
}
theOnlyFunction = async() => {
const value = await someFunctionFromFile( // Pass Parameters );
if( value !== false ) // Just for your understanding I am writing this way
{
this.setState({ number: value })
}
}
render() {
return (
<div>
<p>{this.state.number}</p>
<button onClick={this.double}>Double up!</button>
</div>
);
}
}
And in SomeOtherFile.js
function someFunctionFromFile ( // catch params) {
if( //nah don't wanna do anything ) return false;
// and the blahh blahh algorithm
}
you should use react Context
Context lets us pass a value deep into the component tree without explicitly threading it through every component.
here is a use case from react docs : create a context for the current theme (with "light" as the default).
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// Use a Provider to pass the current theme to the tree below.
// Any component can read it, no matter how deep it is.
// In this example, we're passing "dark" as the current value.
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
// A component in the middle doesn't have to
// pass the theme down explicitly anymore.
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use its value.
// In this example, the current theme is "dark".
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
resource: https://reactjs.org/docs/context.html

Categories

Resources