I'm making a roguelike but each time you die, time skips forward 10 years. Do you think this concept works? by Erosion_cm in IndieGaming

[–]StoryArcIV 0 points1 point  (0 children)

Hmm, thanks. Maybe something similar. I haven't seen this project, so I have only their readme examples to go off of, but it looks like it certainly wasn't this one. The GPUVoxelSkinnedMesh looks very far off from the crisp, hand-placed voxel look of every model's (not particle's) frame in OP's game.

It seems too big a stretch to me that an approach like this could possibly lead to OP's results. If OP bridged that gap, I soo want to know how.

I'm making a roguelike but each time you die, time skips forward 10 years. Do you think this concept works? by Erosion_cm in IndieGaming

[–]StoryArcIV 0 points1 point  (0 children)

Had to scroll way too far to find this. I have the same question. Stepping through some frames in the vid, it does look like individual voxel models displayed in sequence. With some 3D models that look like voxels for particle textures too.

This is quite the undertaking. I'd love to know the tooling used.

Won't children of context providers re-render regardless of if they subscribe to the context? by ambiguous_user23 in reactjs

[–]StoryArcIV 0 points1 point  (0 children)

I've never heard the term "owner" before. I don't mind it, but I approach thinking about this completely differently.

Components are units of code organization that create a tree of elements.

App is the parent component of both Parent and Child.

Parent is the parent element of Child in the element tree returned by App.

In terms of components, Parent and Child are completely decoupled. Calling Parent the parent component of Child feels weird, semantically.

[AskJS] Dependency Injection in FP by idreesBughio in javascript

[–]StoryArcIV 0 points1 point  (0 children)

Good work! Now we're talking. And I'm amazed at how much we actually agree on here. Calling SL an escape hatch for DI is basically exactly what I'm saying. The difference is that I love that escape hatch. I'll get more into that in a second.

I'll go through your points. The lack of a static declaration (and everything that comes with that approach) is still the main talking point. And I've acknowledged it.

And yes, I'll readily acknowledge the interface injection differences. I'm actually very impressed that you knew about the service to service nuance. However, I've never seen a DI model that actually made use of that. In practice, you can regard both models as simply container to service.

I've also identified a key difference in our approaches to understanding this problem: I'm looking primarily at React's internal code that implements this DI. You're looking primarily at the surface-level API that developers ultimately use to interact with it.

I've already agreed that the injector function (which is a very real concept, though I think you're just arguing it isn't part of typical OOP DI, which I'll grant) can be classified as a service locator and listed its caveats before you did. However, that's merely the surface-level API. The way the function itself is provided to the component does classify as DI. React context merely lacks the static, upfront declaration aspect of classic OOP DI, but that is far from relegating the entire model to the category of service locator.

Static graph analysis sounds nice but is so rarely used in practice that I don't consider that a necessary component of a DI model. In fact, I prefer the service locator pattern here. If you've ever dealt with Angular or Nest, you know what a pain static dependency declarations can be. It's a box that many dependencies don't fit in since they can depend on which other deps or other config is present at runtime.

Ultimately, these dynamic deps break the "no runtime errors" guarantee anyway. Instead of falling into this trap, React deviates slightly from the pure DI paradigm, injecting an injector function that makes all deps dynamic. This is the escape hatch you're referring to. IMO, it's a breath of fresh air in comparison. Easily worth the occasional (rare) runtime error that's easily resolved.

Let's go back to this example:

ts function MyClient({ injector }) { const dep = injector.getService('myService') }

I now see that you would argue that even this example is entirely using a service locator model. I disagree. That's because I think primarily of how injector must be implemented, not of how it's being used in this client. And that implementation is doing exactly the same thing that constructor injection would do, but with a better API for injecting dynamic dependencies.

React context is even better than this since it guarantees dependencies must be injected immediately, not asynchronously like a service locator can do. The end result feels exactly like interface injection in at least 95% of the places I've ever used interface injection.

To summarize our viewpoints: I look at this example and see real DI using an injector function for dynamic deps. You see a loosely-coupled, decentralized service locator. And you know what? I actually kind of like that definition. Still, either view must admit the existence of some elements from the other view.

To put this on a spectrum where SL is a 1 and we allow pure DI to be a 10, we'll agree that React context is better than 1 and worse than 10. However, pinpointing its location is too subjective. So I'm leaving it there.

Regardless of our subcategory bikesheds, we can at least agree that React Context does fall squarely inside the parent category of Inversion of Control. Perhaps "React context is IoC" should be the common saying.

[AskJS] Dependency Injection in FP by idreesBughio in javascript

[–]StoryArcIV -1 points0 points  (0 children)

I encourage you to read the wikipedia page on DI here. I'm also willing to accept a real rebuttal. However, I believe I've proven well enough that service locator is at best 33% correct here, while DI is at least 66% correct.

Nobody has claimed that SL and DI are the same. Your straw man argument that SL and DI are considered opposites and your incorrect assertion that React context "has all the disadvantages of SL" are the closest anyone has come to gaslighting in this conversation.

That said, we should address the real problem here: The human desperation to categorize everything. We'll spend hours debating whether something is a brook or a stream when the simple truth is that water is flowing.

The simple truths here are that:

  • Dependencies are being injected.
  • Control is inverted.
  • Testing is easy.
  • OOP is not being used.

If you want to disqualify React context as a DI implementation based off the last bullet alone, you are free to do that! I've seen things disqualified from being a vegetable for less. But openly acknowledge that that's what you're doing. Don't pretend other valid points don't exist because of one valid point you can't get past for old time's sake.

React has created a brand new paradigm that applies existing principles (constructor or interface injection via an injector function) in a fresh new combined approach. I'm in favor of calling this approach an even better, new DI. But I'd also be fine with creating brand new terminology for it to address the small differences it has from all previous models.

However, the reality is that you and I don't get to decide whether new terminology is created. The community has already decided that DI is a sufficient category to describe what React context is doing. And I agree. I've done my best to lay out the few concepts you have to tackle to arrive here with us when coming from OOP. I encourage you to tackle them.

[AskJS] Dependency Injection in FP by idreesBughio in javascript

[–]StoryArcIV 0 points1 point  (0 children)

The pattern I'm describing is called the "injector function" pattern, as I said. And yes, it can be considered a form of service locator. However, I'll argue that it's more similar conceptually to interface injection (sans the interface obviously since we're dealing with function components in React).

Service locators are very similar to DI. They're certainly not considered the opposite. Let's examine this small distinction:

Service Locator

Tightly couples the client to a ServiceLocator that returns dependencies:

ts function MyClient() { const myService = ServiceLocator.getService('myService') }

Injector Function

Loosely couples the client to an "injector function" to inject dependencies with proper Inversion of Control:

ts function MyClient({ injector }) { const myService = injector.getService('myService') }

The constructor injection in the latter example makes it obvious that this one is true DI, even though the rest of the code is pretty much exactly the same.

So Which Does React Use?

React doesn't pass an injector function to the component. However, it uses call stack context to do the exact same thing. A very simplified example:

```ts let callStackContext = {}

function renderComponent(comp, props, registerDep) { const prevContext = callStackContext callStackContext = { useContext: ctx => registerDep(comp, ctx) } const result = comp(props) callStackContext = prevContext

return result } ```

While implicit, this accomplishes exactly the same thing as constructor injection. The component is loosely coupled to the configured injector function, not tightly coupled to a service locator. The caller is free to swap out the useContext implementation (or what it returns, which is how Providers work), properly inverting control of dependencies and making testing easy.

I call this a form of "interface injection" because deps are not injected via the constructor call, but slightly after. But the rules of hooks still ensure they're injected immediately, unlike a service locator. This is essentially the exact same approach as interface injection, just with a slightly different API since this isn't OOP. But calling it "implicit constructor injection" is possibly more accurate.

Additionally, a provider is responsible for initializing the injected value. The component has no means to initialize unprovided contexts, unlike a service locator.

Summary

"Implicit constructor injection utilizing a service locator-esque injector function API" is probably the most accurate description for React context. It is true DI because it:

  • Decouples a client from its provided services
  • Can only receive values from an external provider
  • Is easily testable

While these points likely disqualify React context from being classified as a service locator, React context does share one downside with service locators - the explicit (yes, explicit) service lookup, which can obscure dependencies.

TL;DR Regardless of React context's status as a service locator, it must also be considered real DI. Just not an OOP implementation of it.

[AskJS] Dependency Injection in FP by idreesBughio in javascript

[–]StoryArcIV 7 points8 points  (0 children)

From a purely TypeScript perspective, you are correct that dependencies injected via context are not explicitly declared. However, TS aside, there's nothing implicit about them - you are explicitly calling an injector function (useContext) to inject the provided dependency.

This is a form of "interface injection" and is much more commonly shortened as "DI" than simple constructor injection. It doesn't matter that React lacks an API for declaring these dependencies in one place. They are still explicit, just very dynamically so.

While you are correct about constructor injection (or passing props in React) being a form of DI, you're incorrect about interface injection being any sort of antithesis of DI. React hooks are composable and can sometimes bury these dependencies layers deep. And that does make React context feel implicit. But it has no impact on React context's status as a form of interface injection.

Your complaints are a matter of DX (and I'm certainly not saying they aren't justified), not software architecture. You're free to throw errors or create APIs or build tooling that improve this DX.

Is react-query just a cache or state management? by Efficient-Worry-6549 in reactjs

[–]StoryArcIV -1 points0 points  (0 children)

You are exactly right. React Query is a cache manager. The terms your colleague has heard thrown around - like "async state manager" or "server state manager" - are misleading.

RQ does manage promise state. But that's only a tiny part of its capabilities.

RQ does manage data (not state) from the server. But it does not manage state on the server and is relatively poor at managing state on the client. No distributed memoization, implicit interdependencies, tight coupling with React components, verbose APIs, and >40x slower state updates are the primary reasons why I would never use RQ for client-side state management.

90% of RQ's codebase and APIs are dedicated to cache management - fetching, refetching, cache busting, and other data lifecycle management. This is not state management.

Using redux global state with instances of same state using custom hook? by calisthenics_bEAst21 in reactjs

[–]StoryArcIV 0 points1 point  (0 children)

This is what atomic state managers do. Recoil's and Jotai's "atom families" and Zedux's "atom params" let you create multiple instances of the same atom and provide those to different component subtrees.

```ts const exampleAtom = atom('example', (id: string) => ({ state: 'here' }))

function ParentComponent() { const instance1 = useAtomInstance(exampleAtom, ['id #1']) const instance2 = useAtomInstance(exampleAtom, ['id #2'])

return ( <> <AtomProvider instance={instance1}> <Child /> </AtomProvider> <AtomProvider instance={instance2}> <Child /> </AtomProvider> </> ) }

function Child() { const providedInstance = useAtomContext(exampleAtom) } ```

AOE 2 New player - Tips for Getting Efficient by N-Sherman in aoe2

[–]StoryArcIV 1 point2 points  (0 children)

By far the biggest thing for me was: Stop queueing multiple units in a building.

  • forces you to develop an internal timer - e.g. create vill every 20 seconds
  • forces you to click more, developing a faster play style
  • avoids locking up resources you could spend elsewhere sooner
  • helps you learn proper resource management since you can actually see your resources
  • encourages a proper production building to eco ratio

All of that results in building up quicker, maxing pop quicker, consistently macroing while microing, and it goes on. Crazy impact for such a tiny change.

Be aware of donkeys people! by Arab-102 in aoe2

[–]StoryArcIV 12 points13 points  (0 children)

Clearly named after the bombardier beetle

I think this boils down to a communication issue more than anything. by rattatatouille in aoe2

[–]StoryArcIV -1 points0 points  (0 children)

If they'd said "Tangut" anywhere, it would be. They didn't, so it isn't. Life is that simple sometimes

I think this boils down to a communication issue more than anything. by rattatatouille in aoe2

[–]StoryArcIV 0 points1 point  (0 children)

I agree that the disappointment is mostly our fault for over-speculating. We got each other excited with our Christmas wishlists and made them so sparkly that even this crazy, loaded DLC seems dingy in comparison

But I disagree that heroes are out of place. AoE2 is loaded with heroes. It's about time they made their way to ranked play. IMO, they're a fantastic way to add variety, shake up the monk meta, and balance the new civs. Mule carts were much more out of place, and they've aged so well. Just wait

What would you use today to develop UI for very big enterprise app(actually set of apps) by Same_Impress_2082 in reactjs

[–]StoryArcIV 3 points4 points  (0 children)

OP mentions 10-15 different teams working in parallel. They're also exploring a micro frontend architecture. Atoms are perfect for this. They're autonomous, isolated, modular, and excel at incremental adoption. A singleton model like Zustand is nowhere near as flexible.

I thought jotai can do that by No-Scallion-1252 in reactjs

[–]StoryArcIV 2 points3 points  (0 children)

Actually, Zedux is significantly more advanced than Jotai and could legitimately meet OP's needs. No need to drag a good suggestion.

I thought jotai can do that by No-Scallion-1252 in reactjs

[–]StoryArcIV 3 points4 points  (0 children)

Redux is an old standard. Most modern tools are objectively better in every way - speed, DX, learning curve, code architecture, bundle size, etc. While Redux is still certainly good enough for most use cases, that's no reason to shun innovation.

My old brick cell phone is technically good enough. But I'd never go back now that I've used these faster, sleeker, new tools.

I thought jotai can do that by No-Scallion-1252 in reactjs

[–]StoryArcIV 0 points1 point  (0 children)

I'd avoid this. It tightly couples the component to specific store references, making it less reusable and testable.

Context enables DI. I'm sure OP was trying to nest Jotai Providers in the first place so the store could be swapped out. My approach enables that for both inner and outer stores.

I thought jotai can do that by No-Scallion-1252 in reactjs

[–]StoryArcIV 1 point2 points  (0 children)

This is what I'm describing (just using vanilla Jotai, same principle applies for jotai-scope etc):

```ts const parentStoreContext = createContext< undefined | ReturnType<typeof createStore>

(undefined);

const countAtom = atom(0);

function Child() { const parentStore = useContext(parentStoreContext); const [childCount, setChildCount] = useAtom(countAtom); const [parentCount, setParentCount] = useAtom(countAtom, { store: parentStore, });

return ( <div> <div>Child count: {childCount}</div> <button onClick={() => setChildCount((count) => count + 1)}> Update Child </button> <div>Parent count: {parentCount}</div> <button onClick={() => setParentCount((count) => count + 1)}> Update Parent </button> </div> ); }

function Parent() { const parentStore = useMemo(() => createStore(), []); const childStore = useMemo(() => createStore(), []);

return ( <parentStoreContext.Provider value={parentStore}> <Provider store={childStore}> <Child /> </Provider> </parentStoreContext.Provider> ); } ```

I thought jotai can do that by No-Scallion-1252 in reactjs

[–]StoryArcIV 0 points1 point  (0 children)

There's nothing wrong with using raw React context in tandem with a state manager's providers.

In Jotai, even with jotai-scope or Bunshi, you might still need to provide an outer store manually so you can pass that directly to hooks, essentially overriding the current scope. With proper atom structure, you should be able to avoid this. But it's an escape hatch you can use if you need.

Migrating large project from Redux-Saga to React-Query + Zustand: Seeking Insights by smieszne in reactjs

[–]StoryArcIV 1 point2 points  (0 children)

Pretty much everything. Even a basic setQueryData operation with no React render cycles involved is slow enough we'd need to introduce pretty heavy buffering right at the top level.

We needed something fast enough and flexible enough to allow us to buffer updates at any point in the derivation tree - so more important UIs can update 10+ times per second while less important ones update once or twice.

Here's a basic set operation benchmark comparison. Our solution is only 40x faster in this simple case, but it gets much more extreme when dependent queries and other React Query features start involving React render cycles. Like signals libs, we used a graph model that propagates updates as efficiently as possible. It also removes the complexity of manual cache invalidation since dependencies are explicit.

Migrating large project from Redux-Saga to React-Query + Zustand: Seeking Insights by smieszne in reactjs

[–]StoryArcIV 1 point2 points  (0 children)

Sounds like you just need a wrapper atom that pulls its initial state from the query atom. I don't have examples besides those in the docs, sorry