concur-js icon indicating copy to clipboard operation
concur-js copied to clipboard

Sharing State Between Components

Open mattferrin opened this issue 4 years ago • 3 comments

I see the "Good Boy" throttle example. I feel like it would be possible to use a similar technique to listen for events from other components. In this way, I feel I could essentially share state between components by extracting it from events.

Is there a different recommended approach to sharing state between components?

mattferrin avatar Jun 10 '20 00:06 mattferrin

I don't have a good idiomatic solution to inter-component state sharing yet. I suppose in Javascript you could simply use shared variables but that's not great.

Do you have a usecase where you would want to use it? I feel the way forward would be to analyse lots of usecases to come up with a good solution.

ajnsit avatar Jun 10 '20 11:06 ajnsit

I guess I don't have a use case. I do have a perceived convenience issue. Granted, experimenting with the framework for the first time yesterday, I got the sense that "simply use shared variables" might work surprisingly well.

I pseudo-coded this conceptual solution using an in editor linter as an aid:

class ExhaustiveReturns {} // placeholder, helps insure thorough paths through functions

type StoreOutput<T> = [
  T, // getter
  (t: T) => ExhaustiveReturns // setter
];
// shareable state
type Store<T> = StoreOutput<T>;

// converts tuple to tuple of "Store"s
type MapToStore<T> = { [K in keyof T]: Store<T[K]> };

type ComponentInput<Tuple> = { stores: MapToStore<Tuple> };
// a component type that has access to "Store"s on each render
type Component<Tuple> = (input: ComponentInput<Tuple>) => ExhaustiveReturns; // placeholder type for JSX return

type BuildStoreInput<T> = { initialValue: T };
// initializes a value you wish to share
function buildStore<T>(input: BuildStoreInput<T>): Store<T> {
  throw new Error("not implemented");
}

type BuildComponentInput<Tuple> = {
  stores: MapToStore<Tuple>;
  component: Component<Tuple>;
};
// gives a component access to the "Store"s it needs
function buildComponent<Tuple>(
  input: BuildComponentInput<Tuple>
): Component<Tuple> {
  throw new Error("not implemented");
}

// example ...

const storeNumber = buildStore<number>({ initialValue: 1 });
const storeString = buildStore<string>({ initialValue: "2" });
const storeBoolean = buildStore<boolean>({ initialValue: false });

const Component0 = buildComponent<[]>({
  stores: [],
  component: (_stores) => {
    throw new Error("not implemented");
  },
});

const Component1 = buildComponent<[string, boolean, number]>({
  stores: [storeString, storeBoolean, storeNumber],
  component: ({
    stores: [
      [valueString, setString],
      [valueBoolean, setBoolean],
      [valueNumber, setNumber],
    ],
  }) => {
    // silly console.log usage in render
    console.log(
      valueString,
      setString,
      valueBoolean,
      setBoolean,
      valueNumber,
      setNumber
    );
    throw new Error("not implemented");
  },
});

const Component2 = buildComponent<[boolean, string]>({
  stores: [storeBoolean, storeString],
  component: ({
    stores: [[valueBoolean, setBoolean], [valueString, setString]],
  }) => {
    // silly console.log usage in render
    console.log(valueString, setString, valueBoolean, setBoolean);
    throw new Error("not implemented");
  },
});

mattferrin avatar Jun 14 '20 06:06 mattferrin

I have been struggling to merge what I know with the style I see from your framework.

So, this is what I think it really boils down to:

To share state between components, you must re-render the new state. You can still use async generators to yield components, but the yielded component needs to maintain the ability to re-render between yields.

So, if concur-js chooses to yield React components, concur-js can control program flow while React programmers continue to share state between components in whatever way they already do.

But since concur-js should have access to the same state as its React components do between yields, it might as well interop with Redux (popular even if I don't like it) and other various state management libraries as much as possible.

mattferrin avatar Jun 14 '20 07:06 mattferrin