How can I avoid global state when programming with React? - reactjs

Tons of examples, describing React and Flux uses global variables: global Dispatcher, global Store and etc. Is there any way to proper inject dependencies to react components? There are some articles on the web describing how to use Dependency Injection component with React, but it based on undocumented weird feature called "Context" with unknown future.
Proper injection, for me, is classic constructor-based injection, without accessing global variables, without accessing static state and other.
It seems that I need to hook into component construction process (place, where new called). Can I do that? If so, how can I do that?

The most straightforward way to do dependency inversion with React is to simply pass any necessary dependencies as properties to the components that need them. Context is simply a way to pass the props down through child components, grandchild components, and so on implicitly without listing the prop on every component that may need it.
You'll find a lot of examples of this technique in the wild, and many make use of context and other niceties. React Redux is a popular one right now; pass a local variable to a top-level <Provider> component as a property, and it wires up the rest for you.
Dependency injection is less straightforward, and you'd probably need some kind of proper DI container or a DI library for JavaScript to do this nicely. Components aren't really instantiated, from the user's standpoint, the way other JS objects are, so doing "at instantiation time" injection of dependencies into components isn't how I'd approach the problem.

Related

Call a components local function from other distant component(s)

I have a function that interacts with local state/hook that I want to be able to call from other distant component(s)
For instance, calling a React Apollo mutation that has local side-effects from the response in that component from other areas. Also keeping code DRY without duplicate the hook in everywhere its used, and setting global state that is only read in this one component.
Another similar use-case would be calling a refetch() from specific UI elements - like a button in a distant component (so refetchQueries would not be applicable here)
Let me know if additional clarity or a specific example would help.
Options I've considered:
EventBus: there seems to be little about event buses as a recommended approach. Most posts link to React recommending this in old docs from years ago. It seems feasible, potentially could even setup a pubsub with hooks, but I'm not sure if it's an anti-pattern. In Vue it is common.
Global State:, Context would seem to be overkill for such a specific and small use case, but I am already using an atomic state library. I could set an atom to hold the function on mount, and call the function from the atom where I want.
What would be some practical ways to do this? I'm curious as to other possible approaches, trade-offs, or insight into other implementations you may have used.

How do hooks replace components?

Hooks, as I understand them, are just a way to add state (and lifecycle methods) to function components.
This FAQ answer:
In the longer term, we expect Hooks to be the primary way people write React components.
https://reactjs.org/docs/hooks-faq.html#should-i-use-hooks-classes-or-a-mix-of-both
and this documentation snippet:
Hooks let you split one component into smaller functions based on what pieces are related
https://reactjs.org/docs/hooks-intro.html
confuse me slightly as a React beginner.
It is as if I have to think about my app in terms of hooks rather than in terms of elements and components.
React didn't remove components, but the quote hints that hooks will replace
components as the primary source of code reuse.
Can one still talk about elements and components as primary abstractions in React?
The concept of components is not going away, it's just how they are written that is changing.
The second line you quoted
Hooks let you split one component into smaller functions based on what pieces are related
Is poorly worded in my opinion, and should rather say "Hooks let you split one class component into smaller functional components..."
So instead of having one monolithic class that handles all state and lifecycle logic in methods like componentDidMount, componentDidUpdate, you can split areas of concern and have smaller functional components that only care about things directly related to themselves.
Edit: This snippet from the hooks-intro doc might be helpful:
Hooks don’t replace your knowledge of React concepts. Instead, Hooks provide a more direct API to the React concepts you already know: props, state, context, refs, and lifecycle. As we will show later, Hooks also offer a new powerful way to combine them.
Currently, there are 2 ways of building components in React:
Class Component
Functional Component
You can check them here. The way you build it it's different. In case you approach the class component, that means that you need to work with the prototype of the object.
On the other side, if you choose to go as a functional component, that means that everything you request from React, is invoking a function, and not using the prototype at all. All this chaining from JS can slow down the performance, and that's why the React core team decided to go into pure functional direction: It can perform better, and it makes it even simpler to read it (once you get used to it).
Regarding the second quotation. It is a way to show more benefits of functional programming over classes. They are more flexible and can have a better composition for it.
One last addition: Approaching functional components doesn't mean you can ignore to learn class components. There's still a lot of apps with some legacy code. I would recommend learning both, and whenever you need to create new components, approach the functional component paradigm.

How to pass authentication in React?

Without some global state management library like Redux, what would be a good way to pass the user around through my components? I'm using Firebase, so I'm imagining my top-level app component will be listening to auth changes and storing the user somewhere. Here are the options I've thought of:
Passing 'user' to each route in props (and on to children that need it)
Using a global object of my own
Using Context
1 seems like a hassle.
2 doesn't seem like the right way and like more of a hassle, wouldn't I have to listen for changes and set the user in my states? It's what they show in the React Router docs but I'm guessing that's just for simplicity's sake and not best practice.
3 seems like the best way to me but it seems like it's discouraged:
The vast majority of applications do not need to use context.
If you
want your application to be stable, don't use context. It is an
experimental API and it is likely to break in future releases of
React.
I would still say that you use context. It's the best way I have found to thread a common state throughout the react tree.
Even though they discourage it, all popular react libraries (including react-redux) use it big time. It's not going to be removed any time soon. And the use case seems very legit, provided you know what you are doing.

Is it sane to use React `context` to access model mutators in a Flux-less app?

I'm starting a new React app and, seeing all the news in the ecosystem, I want to go slow and actually consider my choices, starting with just React/Webpack/Babel, and introducing more.
The first of these choices is whether to use Flux or not (more precisely, Redux, which looks great and seems to have won the flux wars). Here is where I am:
I understand Redux's benefits, summarized on SO by Dan Abramov. They look great, but I'd rather introduce things one step at a time.
In plain React, parent→child communication is done with props, and child→parent communication happens with callbacks. See Doc / Communicate Between Components, or SO / Child to parent communication in React (JSX) without flux, or this codeacademy Redux tutorial which starts out by saying "no need for Redux if you're fine with plain React and all your data in a root component".
Which looks just fine for my purpose...
... however, the sad part is that these callbacks have to be passed down the component chain, which becomes quickly tedious as the levels of nesting grow.
To solve this without introducing new dependencies, I found two articles (1: Andrew Farmer, 2: Hao Chuan) encouraging usage of the recently-introduced context feature of React.
→ Using context would let me expose my model-mutating callbacks to my child components. To me it doesn't sound like a horrible misuse: I wouldn't be passing model data, just references to functions for binding on event handlers.
Does it sound sane?
Any other plain-React suggestion for convenient child→parent communication?
Thanks.
Answering my own question after watching Dan Abramov's Getting Started with Redux series, which I warmly recommend.
Yes it looks like it's sane: Redux faced the very same problem and solved it with Context (at least initially, the implementation may have changed). It is implemented and packaged (among other things) in the react-redux bindings under the <Provider> component and the connect() function.
Initially, at the start of step 24 - Passing the Store Down Explicitly via Props , we have a Todo app with a Redux store available as top-level variable. This sucks (for 1. testability/mockability, 2. server rendering needing "a different store instance for every request because different requests have different data"), so the store is demoted from top-level variable to a root component prop.
As in my case, having to pass the store as prop to each component is annoying, so in 25 - Passing the Store Down Implicitly via Context, Dan demonstrates using Context to pass the Redux store to arbitrarily nested components.
It is followed by 26 - Passing the Store Down with <Provider> from react-redux, explaining how this was encapsulated in the react-redux bindings.
And 27 - Generating Containers with connect() from React Redux further encapsulates generation of a container component from a presentational component.
Personally, I find the question quite simple to answer, if you think about the way dependency injection in Angular works. In Angular you have your DOM, and then you have all those services, providers, factories, constants and whatnot, which are independent of the DOM structure and can be imported simply by mentioning their name when creating modules or controllers.
I liken the use of this.context to DI. The difference w.r.t to Angular is that instead of stating the dependencies using function parameter names, you use childContextTypes and instead of getting the dependencies as function arguments, you get them through this.context.
In this sense, asking the question whether passing model mutators through this.context is sane, boils down to whether it makes sense in Angular to register your model for dependency injection. I've never seen a problem with the latter, therefore I deduce that the former is also quite OK.
I'm not saying that it suits the spirit of the library, though. Dependency injection and in particular managing dependencies between injected component is not as explicit, so one may argue that it's not the React way. I leave this philosophical discussion to others.

Storing a React element in Redux state: anti-pattern?

Is it advisable or even possible to include a React element in a Redux store's state? Since it is a plain object describing "what should be drawn", I guess it should be safe, but still: any experience out there?
Why would I want to do such a thing? I'm writing an abstract React component capable of embedding other components, described elsewhere in the React tree. This would allow them, for instance, to escape from the physical boundaries of a hardware-accelerated, CSS-transformed DOM node, used for performance.
Yes - as with many other similar ideas, it's possible, but is absolutely an anti-pattern because it breaks the ability to do things like time-travel debugging (one of Redux's core selling points). See the Redux FAQ at http://redux.js.org/docs/FAQ.html#organizing-state-non-serializable for further details.
Now, keeping React component classes in a React component's internal state is different, and might be useful for cases like dynamically requiring a component and re-rendering once the implementation has been downloaded.

Resources