As a non native english speaker, i am confused by the term "passive effects", as in schedulePassiveEffects, cancelPassiveEffects in React source code.
What exactly does 'passive' mean here?
The reason why it's not just called effect is that there're other Effects in React. There're mutation effects and layout effects along with passive ones.
The passive one is the common one which listens to a state change (through a dependency array) and then can invoke a callback that changes other states.
What's unique about a passive effect is, it waits for all UI (render and commit) to settle down before invoking them in another time slice. So the callback happens in a Javascript time slice similar to an event handler (ex. onClick).
I believe this is where it gets its name, the "passive". Because instead of actively handling an event, it's passively listen to a state change and invoke a callback. I wrote a blog about this, https://javascript.plainenglish.io/is-a-react-passive-effect-an-artificial-event-2535977b9a91
Related
It seems to me the trend is replacing Redux with React Context API and useReducer.
I personally do not like a huge store at root with states from user data to if a dialog is opened all mixed together.
Switching to React Context API allowed me to push the state down and closer to where they will be used. However I can only push it down to the level that child components are either displaying or modifying that value. For example:
<Parent>
<CounterDisplay/>
<CounterIncreaseButton/>
</Parent>
I have to have count on Parent and create a Context. Within the Context, I'll add the count value and an increaseCount method (or a state and a dispatch function when use reducer pattern). Then I provide the context to those 2 child components. Now one can display it and one can modify it.
Now what if I need another button located far from this part of the component tree that also need to change the count value? I have to lift the state up and maybe all the way to the root. That feels strange to me.
2nd issue is when states are scattered at multiple level along the path in the tree, when something happens say user click a button, you may need to call multiple functions from multiple contexts (or dispatch multiple actions, one for each state that may or may not change). Unlike when use Redux since everything is at the root, you just need to dispatch one action.
So what if instead I have an event pub/sub at the root level? I can have the counter state and code manipulate it pushed down even more to CounterDisplay. CounterDisplay need to subscribe to the pub/sub system and listen to the event and update counter correspondingly. And whichever component want to change the counter can just raise an event.
What am I missing in this pattern? Circular event loop? Raise conditions? Feels a good pub/sub library can prevent these. I looked around and did not find something existing. I looked at RxJS but don't feel that fits.
Thanks in advance for sharing your thoughts.
You've basically just described the exact reason for Redux to exist :)
Redux is "an event pub/sub at the root level", and can specifically be beneficial in cases where widely separated components need to make use of the same data.
You may want to read my post Redux - Not Dead Yet!, which describes how Redux fits into today's ecosystem (including comparisons vs context) and some of the reasons you might find it useful.
If you are put off redux by the amount of boilerplate.
I would suggest taking a look at redux-zero.
Under the hood. react-redux uses a context provider at the root.
When you use the connect Higher-Order-Component that is using the context.
Same with the redux hooks.
So it's quite normal to have the provider at the very top.
It would be the same for any library like the react-router to do the same.
I would suggest you keep trying without redux so you can learn more. Put the provider at the root. It won't impact performance in anyway.
Isolate the context you create and the provider to a singleton file and import it to the components you need
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.
I'm still studying the Flux architecture, and noticed that:
one Action can cause multiple Stores to emit a "change" event
one ControllerView can be subscribed to the "change" event of multiple Stores
So, if ControllerView depends on data of two Stores, and those two Stores are both changed by one Action, the ContollerView - with all its components - will be rendered (to the virtual DOM) twice, the first time with incomplete data.
Is there any recognized pattern to avoid this? I can think of some simple solutions, but I wouldn't like to reinvent the wheel.
In general, you should just allow it to render more than once. However, the if the action always triggers actions in both stores you can use the "waitFor()" method of the dispatcher to let one store update first, then only emit a change when the second store gets updated.
This is only useful if the action will always affect both stores, however.
Best practice in flux pattern is to limit number of stateful components, and try only to have top component listen to stores, and send down all relevant info in props.
With multiple stores, one solution to minimize multiple renders after a single change:
create a StatStore that stores nothing, but listens to all relevant Actions, and waits for all other relevant stores.
this StatStore has getter functions, that collect (and possibly calculates stats) from other stores
your top component only listens to StatStore change emissions
top component then gets data from StatStore.
That way, a single change only results in one re-render.
I'll add this for future reference: I didn't find any good solution to this problem with vanilla Flux, and in the end switched to Redux, which has all the advantages of Flux and doesn't suffer from this disadvantage.
After having built a few apps using (what I believe) to be a Flux architecture based off a framework I built, I wonder what it means when:
Mozilla says:
"The dispatcher dispatches actions to interested stores. Only one
action can be processed at any one time."
Or Facebook says:
"We need the dispatcher to be able to invoke the callback for Store B,
and finish that callback, before moving forward with Store A."
Why I'm confused is because Javascript's concurrency model only allows one thing to happen at once, and ensures the call stack of the current action is depleted before it moves on with the task Queue.
So we get for free what Facebook and Mozilla says their dispatchers give us. We can't avoid it. Why are we talking about it like it's anything special?
Well... another consideration is if your "action" does something asynchronous with a callback like:
update state,
fire off an XHR,
update state with result.
Here your action can be broken in 2 parts and something can happen in between 2 and 3, thus violating the "one action at a time" principle.
That problem is solved by nothing more than terminology:
Define Action A as the thing that updates state and sends XHR.
result of XHR triggers Action B which updates state.
After all, Facebook has said "Actions may also come from other places, such as the server."
So with a little change in terminology we have no need for a dispatcher that does anything beyond dispatch an event to interested stores.
So what am I missing? Why must a dispatcher in Flux do anything more than dispatch?
My answer is: the people who wrote those bits of documentation weren't clear in what they were talking about.
Even the top stackoverflow React answerer and React contributor says:
In my understanding, asynchronous actions that rely on Ajax, etc.
shouldn't block the action from being dispatched to all subscribers.
You'll have a separate action for the user action, like
TODO_UPDATE_TEXT in the TodoMVC example and one that gets called when
the server returns, something like TODO_UPDATE_TEXT_COMPLETED (or
maybe just something more generic like TODO_UPDATE_COMPLETED that
contains a new copy of the latest attributes).
See: https://stackoverflow.com/a/23637463/131227
This refers to http://todomvc.com/architecture-examples/backbone/.
In app.AppView the render() method gets called many times when adding a single todo.
If I'm not mistaking, having the render() method being called many times is bad. Is this a flaw in the TodoMVC implementation?
In most cases, you'd be right.
In the Todo case, however, it seems only the "add" event gets triggered. This is because there apparently isn't (e.g.) a "sync" event since it uses local storage and doesn't actually sync with the server.
In other words, it looks that isn't the case in Todo's very specific case (due to implementation), but in most cases registering a handler on "all" events would trigger the rendering multiple times.