I know that setState can be passed a callback to execute after the state is set. However I sometimes have code that I want to be executed in order where the state is set "indirectly" several layers down a method call.
For example:
this.makeDirty()
this.doThisAfter()
The makeDirty() call calls several methods, and one of them is responsible for calling another method that sets a dirty flag on the state. Because of this doThisAFter is called before state is set.
I understand that I could try to pass around callbacks all over the place to make sure they get into the setState callback argument, but this would significantly (and seemingly can be avoided) increase the complexity and ugliness of the code.
Is there a community-accepted solution for this? One thing I've thought of is instead of using setState I would always use a wrapper like mySetState that always calls the same callback method, one that looks for the presence of a queue of other functions that can be pre-filled. And then have some kind of API like:
doSyncronously( func1, func2, funcN...)
where the func2...N would be placed in a queue called by mySetState that is called by func1.
The problems with this are numerous, and I feel like I'll probably get it wrong. It also feels like I'm re-inventing the wheel or missing something.
Suggestions / comments?
Related
I've been using React Hooks for a few months and have strictly adhered to using the useEffect hook as per the documentation.
A new colleague has joined the team and he is asking why is useEffect necessary. We've gone through the documentation together but he points out that implementing useEffect causes extra renders.
Here is a simple use case: A button is pressed to fetch some data. The click is handled by a Click event handler. He is wondering why he can't make the async call to the endpoint directly within the event handler.
I'm looking for an explanation that goes beyond "the docs say you shouldn't" and actually explains what the danger or downside of doing this is.
Might anyone be able to share why?
In short it's used for any side effects (not only fetching data):
A side effect is any application state change that is observable outside the called function other than its return value. Side effects include:
Modifying any external variable or object property (e.g., a global
variable, or a variable in the parent function scope chain)
Logging to the console
Writing to the screen
Writing to a file
Writing to the network
Triggering any external process
Calling any other functions with side-effects
Side effects are mostly avoided in functional programming, which makes the effects of a program much easier to understand, and much easier to test.
Haskell and other functional languages frequently isolate and encapsulate side effects from pure functions using monads.
Ok, there is something I don't understand again:
onDateChange(child, performUpdate){
console.log("child", child, child.state);
}
As you can see, from the debugeur, the state has some value. But when I try to access them, they act like if they where not initialized. Like if the setState wasn't an atomic operation after all...
Actually I don't have any idea as it seems counter intuitive.
Can someone help me to get my data from the callback. Every operation in js/reactjs act differently from what it is expected.
Is that because the 'state' property is in another field and duplicated? I can't find any logical reason for this strange behavior.
edit:
So it appear that setState is asynchronuous. And worst part, non atomic operation. This is kind of strange they don't speak of that in the documentation (instead they said to not use state directly but by method call. Why? Because they do the change in another thread without telling the client!!!).
So this is how you have concurrency problem like I had.
Is there a clean approach for this kind of problem? Like a callback on setState method when all the operation are done (some people use delay or inline function, which absolutly don't correct the problem ).
To resolve my issue, I had to use a proxy pattern where there is the datastructure independantly from the view who display it, and act as if it was the same object. So that the controller don't have to deal with all this 'background' threaded operation mess. (Note: the datastructure is not a model, but a readonly object).
So,I've got a component called a Project, which has a child called ProjectDates.ProjectDates receives its parent's start/end dates, and calculates the percentage completion.
I'm currently doing this calculation in render() so that I don't have to do it both in componentDidUpdate and componentDidMount. Is that correct, or is there a more appropriate lifecycle hook that I should be using?
I think all your suggestions are in general wrong. Lets take them one by one:
1) componentWillMount. You can have some logic here - but it is not recommended to introduce any side dependencies here. So in really world when you usually have to interact with back end - its of little help. Must better choice - componentDidMount where you do not have such restrictions.
2) componentWillUpdate. You should be careful here - to not end up with endless loop. Calling setState here is prohibited as it might in calling componentWillUpdate again and so on. Consider using componentWillReceiveProps.
3) render. This method should not contain any other logic except the one that prepares (renders) the content of the component. Consider moving your "business" logic to componentWillReceiveProps/componentDidMount or maybe constructor if applicable.
I recommend to go through the official docs before making decisions about your architecture.
What is the difference between seeding a action and call a 'setter' method of a store in reflux data flow?
TodoActions['add'](todo)
vs
TodoStore.add(todo)
Action will trigger your store via RefluxJS lib, but Store.Add() is calling add method directly
First off, it's useful to note that Whatever.func() and Whatever['func']() are just two different syntaxes for the same thing. So the only difference here in your example is what you're calling it on.
As far as calling a method in a store directly, vs. an action which then ends up calling that method in a store, the difference is architectural, and has to do with following a pattern that is more easily scaled, works more broadly, etc. etc.
If any given event within the program (such as, in this case, adding something) emits 1 clear action that anything can listen for, then it becomes MUCH easier to build large programs, edit previously made programs, etc. The component saying that this event has happened doesn't need to keep track of everywhere that might need to know about it...it just needs to say TodoActions.add(todo), and every other part of the program that needs to know about an addition happening can manage itself to make sure it's listening for that action.
So that's why we follow the 1 way looping pattern:
component -> action -> store -> back to component
Because then the flow of events happening is much more easily managed, because each part of the program can manage its own knowledge about the program state and when it needs to be changed. The component emitting the action doesn't need to know every possible part of the program that might need that action...it just needs to emit it.
When do you use a callback function? I know how they work, I have seen them in use and I have used them myself many times.
An example from the C world would be libcurl which relies on callbacks for its data retrieval.
An opposing example would be OpenSSL: Where I have used it, I use out parameters:
ret = somefunc(&target_value);
if(ret != 0)
//error case
I am wondering when to use which? Is a callback only useful for async stuff? I am currently in the processes of designing my application's API and I am wondering whether to use a callback or just an out parameter. Under the hood it will use libcurl and OpenSSL as the main libraries it builds on and the parameter "returned" is an OpenSSL data type.
I don't see any benefit of a callback over just returning. Is this only useful, if I want to process the data in any way instead of just giving it back? But then I could process the returned data. Where is the difference?
In the simplest case, the two approaches are equivalent. But if the callback can be called multiple times to process data as it arrives, then the callback approach provides greater flexibility, and this flexibility is not limited to async use cases.
libcurl is a good example: it provides an API that allows specifying a callback for all newly arrived data. The alternative, as you present it, would be to just return the data. But return it — how? If the data is collected into a memory buffer, the buffer might end up very large, and the caller might have only wanted to save it to a file, like a downloader. If the data is saved to a file whose name is returned to the caller, it might incur unnecessary IO if the caller in fact only wanted to store it in memory, like a web browser showing an image. Either approach is suboptimal if the caller wanted to process data as it streams, say to calculate a checksum, and didn't need to store it at all.
The callback approach allows the caller to decide how the individual chunks of data will be processed or assembled into a larger whole.
Callbacks are useful for asynchronous notification. When you register a callback with some API, you are expecting that callback to be run when some event occurs. Along the same vein, you can use them as an intermediate step in a data processing pipeline (similar to an 'insert' if you're familiar with the audio/recording industry).
So, to summarise, these are the two main paradigms that I have encountered and/or implemented callback schemes for:
I will tell you when data arrives or some event occurs - you use it as you see fit.
I will give you the chance to modify some data before I deal with it.
If the value can be returned immediately then yes, there is no need for a callback. As you surmised, callbacks are useful in situations wherein a value cannot be returned immediately for whatever reason (perhaps it is just a long running operation which is better performed asynchronously).
My take on this: I see it as which module has to know about which one? Let's call them Data-User and IO.
Assume you have some IO, where data comes in. The IO-Module might not even know who is interested in the data. The Data-User however knows exactly which data it needs. So the IO should provide a function like subscribe_to_incoming_data(func) and the Data-User module will subscribe to the specific data the IO-Module has. The alternative would be to change code in the IO-Module to call the Data-User. But with existing libs you definitely don't want to touch existing code that someone else has provided to you.