RxJS and React's setState - delay function execution until subscription - javascript

RxJS has a nifty function, fromCallback that takes a function whose last parameter is a callback and returns an Observable. And I want to combine that with React's setState function so that I can do something analogous to:
const setState = Rx.Observable.fromCallback(this.setState);
setState({ myState: 'Hi there!' }).concat(....)
so that any operations chained to setState are guaranteed to happen after the state has been set and, most importantly, that setState isn't invoked until there's an active subscriber.
What I noticed though is that even without a subscribe, setState is being called right as it's defined and setting the state of my component. So if I have:
networkSignal.flatMap((x) => {
return setState({ myState: 'test' });
});
the function setState is immediately invoked but the observer it producers won't send a next until there's a subscriber. What I want is for the function to only invoke when there's a subscriber.
Looking into the source you can see that RxJS returns a function that when executed, creates an observable but immediately invokes the function - the callback argument.

fromCallback returns a function which, when executed, returns an observable. That observable is where the asynchronous result(s) of the function call will flow.
To delay the execution of the function, you can make use of .defer. For instance:
const setState = Rx.Observable.fromCallback(this.setState);
const deferred$ = Rx.Observable.defer(function (){return setState({ myState: 'Hi there!' }).concat(....)});
// Later on
deferred$.subscribe(...)
Question whose answers used the same technique were asked here and here

Related

calling setState method with other statements

I know that calling setState method means I don’t have to manually invoke the ReactDOM.render method. Below is some example code:
...
render() {
return (
<button onClick={this.handleClick}>
Click
</button>
)
}
handleClick = () => {
this.setState({ counter: this.state.counter + 1 }, () => this.setState({ hasButtonBeenClicked: this.state.counter > 0 }));
this.props.callback();
}
since there is another statement this.props.callback(); below the this.setState() method, so does ReactDOM.render method get called before or after this.props.callback();?
since there is another statement this.props.callback(); below the this.setState() method, so does ReactDOM.render method get called before or after this.props.callback();?
After, in your case. The state update and call to render is asynchronous if setState is called within a React event handler (and may be asynchronous even if not, more here). The sequence (within a React event handler) is:
You call setState with the state update.
You call this.props.callback();
React processes the state update (possibly combining it with other pending updates).
(Some handwaving here about shouldComponentUpdate.)
React calls render to have it render the current state.
If you want this.props.callback(); called after the new state has been rendered, put it in a function as the second argument of setState:
handleClick = () => {
this.setState(
{ counter: this.state.counter + 1 },
() => {
this.props.callback();
}
);
}
or
handleClick = () => {
this.setState(
{ counter: this.state.counter + 1 },
this.props.callback
);
}
...if this.props.callback doesn't care what this you call it with.
More here:
State Updates May Be Asynchronous (that title drives me nuts, because it's not that they may be asynchronous, it's that they are asynchronous)
setState API docs
If you look at my example of your code, this.props.callback() gets called immediately after the state has been updated.
handleClick = () => {
this.setState({ counter: this.state.counter + 1, hasButtonBeenClicked: true }, () => this.props.callback() );
}
You have chained setStates, which seem unnecessary for readability. These should be grouped into a single setState call automatically, however one is nested into the callback and this would trigger multiple re-renders.. depending on ShouldComponentUpdate.
To avoid guessing or leaving it susceptible to future React updates:
Using the setState callback for this.props.callback, is the best way to ensure it is executed after setState completes.
Updated, based on T.J Crowders feedback and research with event handlers:
The way your code was structured it is most probable that this.props.callback will be called prior to the setState actually completing state updates, it will trigger the re-render once state updates.
-Because, it is in an asynchronous call and within a React event handler. SetState should update state after.(I am still no expert on promises, and have to wonder if there is a chance state could update within the millisecond, depending on your browsers internal clock and the batch processing)
For clarity, to others. This example is asynchronous and that means the code continues to be executed, while waiting for resolution. While setState returns a promise. In this case, it should absolutely continue to process this.props.callback(), until the promise is resolved.

How the callback is executed in this function?

const getData = (cb) => {
setTimeout( () => {
cb({ data: ['there', 'is', 'stuff', 'here'] })
}, 100)
}
getData( data => {
console.log(data);
});
Here is the example of the javascript callback. Could some one let me know how this functions is executed into the javascript callback?
Here what is the function inside getData(cb) ? How it will be executed ? How the functions is passed as callback inside cb and return to the console.log
Regards.
The function inside getData is a callback being passed to setTimeout, which is one way to schedule a call to a function to happen in the future. In this case, it's asking for that callback to happen roughly 100ms later. getData returns before that happens.
The setTimeout callback is a closure¹ over the context where it's created, which means it has access to cb even after getData has returned. So when the browser's timer calls the callback, the callback can call cb. The call to cb uses an object literal to create an object to pass to cb.
In the call to getData, the author is passing a function as cb that logs the data it receives.
So:
getData is called, passing in a function that will log the argument it gets.
getData calls setTimeout to schedule a callback in about 100ms, passing in another function for the timer to call.
getData returns.
About 100ms later, the browser's timer subsystem triggers a call to the callback passed to setTimeout.
That callback creates an object and calls cb, passing the object to it.
That callback (the one passed to getData) logs the data object it receives.
¹ "closure" — see: SO, my anemic blog
In order to understand the code you can just simplify it by naming the anonymous functions. One example could be:
function logData(data) {
console.log(data);
}
const getData = (cb) => {
// `cb` is `logData` function when `getData` is called
function timeoutCallback() {
var data = { data: ['there', 'is', 'stuff', 'here'] };
cb(data);
}
setTimeout(timeoutCallback, 100)
}
getData(logData);
Does that make sense?
1- first global execution context created
2- get data function will be called then it will wait for 10 seconds inside the event loop then it will be come to execution context and printed to console.

Is `setState({key: value}, () => function())` the same as `setState({key:value}, function())`?

Is there any difference between using React's setState() method in the following two ways:
setState({key: value}, myFunction())
vs.
setState({key: value}, () => myFunction())
(edited to use myFunction as in the post).
The two lines of code are quite different:
setState({key: value}, myFunction())
calls myFunction when the arguments are being evaluated, before calling setState. The return value of myFunction is then passed to setState as its second argument. So this version is only useful if myFunction() returns a callback function for use by setState. If myFunction is the callback, however, then it's a bug which could manifest itself as the callback being called prior to the state being updated instead of afterwards.
setState({key: value}, () => myFunction())
creates an anonymous call back function which when executed returns the return value of calling myFunction. The arrow callback function is passed as the second argument to setState, without calling myFunction in the process. myFunction will then be called after setState has updated the state and called the arrow function.
The second form is generally better written without creating an anonymous function intermediary:
setState({key: value}, myFunction)
Although possibly unrelated to the question, an arrow function could be used to set the this value of myFunction to the this value prior to the call to setState:
setState({key: value}, ()=>this.myFunction); // use current this value in the callback.

In simple terms, what's the difference between a thunk and a Higher Order Function?

I understand that both are functions that return functions.
My experience so far with thunks have been using them to return functions as opposed to just action objects so that I can work with async requests in Redux.
A closure is an implementation of a High Order Function (HOF) in order to create a new scope for private variables...right? Other examples of HOFs include map, reduce and filter.
Is there any thing else that explicitly defines a difference between the two?
Thanks.
I understand that both are functions that return functions
Your understanding is slightly incorrect
Thunks can return a value of any type – not just a Function type
Higher-order functions can return a value of any type – not just a Function type
My experience so far with thunks have been using them to return functions as opposed to just action objects so that I can work with async requests in Redux.
Thunks (and higher-order functions, for that matter) are not intrinsically related to any particular library (React, Redux) or any particular control flow (sync, async). A thunk is just a nullary function – they have a variety of common uses cases, but most commonly are used to delay the evaluation of a specific computation.
A closure is an implementation of a High Order Function (HOF) in order to create a new scope for private variables...right? Other examples of HOFs include map, reduce and filter.
A closure is not necessarily an implementation of a higher-order function. The function keyword (and => arrow function syntax) does create a closure tho which does have a new (lexical) scope, yes.
Is there any thing else that explicitly defines a difference between the two?
Yes. How they are the same:
they are both functions
they can both return values of any type
How they are different:
thunks are nullary functions (they accept no arguments)
higher-order functions accept a function as an argument and/or return a function
Perhaps the most critical distinction:
A thunk can only be considered a higher-order function if it returns a function.
Thunks are functions wrap expressions in order to delay their evaluation.
This delay is achieved in Redux thunk a when an action is called it returns a function. This function that is returned can then be called at a later time.
Here is an example of a thunk action.
function incrementAsync() {
// the below function is called by Redux Thunk middleware below.
return dispatch => {
setTimeout(() => {
// Yay! Can invoke sync or async actions with `dispatch`
dispatch(increment());
}, 1000);
};
A higher order function is just a function that either returns a function or takes a function as one of its arguments. Because this function returns another function that takes dispatch as an argument this is an example of a higher order function.
The code from the redux thunk middleware resembles this
function createThunkMiddleware() {
return store => next => action => {
if (typeof action === 'function') {
// since action is a function it is a thunk action creator
// so call it with store methods
return action(store.dispatch, store.getState);
}
// action is not a function so redux thunk ignores it
return next(action);
};
}
As soon as our thunk action creator is called it sends the action function through the middleware chain. When it reaches our thunk middleware this action is recognised as a function and therefore called again with the dispatch and getState methods of the store.
Because of this second function call we are now in the scope of the returned function from our thunk action creator. This means that we can now execute asynchronous logic and still have access to the store's getState and dispatch methods. This is why our thunk action creator can be considered a thunk expression. By using a higher order function we can have access to, yet postpone the use of the store's dispatch or getState method to a future time. As seen below, the increment action is called after a one second delay.
function incrementAsync() {
// the below function is called by Redux Thunk middleware below.
return dispatch => {
setTimeout(() => {
// Yay! Can invoke sync or async actions with `dispatch`
dispatch(increment());
}, 1000);
};

Fulling updating setState in reactjs

In the reactjs docs for setState:
setState() does not immediately mutate this.state but creates a
pending state transition. Accessing this.state after calling this
method can potentially return the existing value.
The second (optional) parameter is a callback function that will be
executed once setState is completed and the component is re-rendered.
What if I just wanted to update my state, do I create a callback that does nothing?
As they write setState() does not immediately mutate this.state but creates a pending state transition. because it works in an asynchronous way. So if you want to perform an action immediately after setting state on a state variable then a callback will be useful.
For Example
setState(
{ name: "Hello World" },
() => console.log(this.state)
);
The callback is optional so you can do this.setState({ key: value });.

Categories

Resources