keajs / kea

Batteries Included State Management for React

Home Page:https://keajs.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Updating part of connected logic

rschyboll opened this issue · comments

It's me again :)
This question is somewhat related to the previous question, as it is about the same part of code, just extended a bit (#143).

Maybe the best way would be to explain what i would like to accomplish, as currently i'm not really sure if it even would be possible.

import { kea } from 'kea';

import type { someLogicType } from './someLogicType';

type WidgetData = {}; 

export const someLogic = kea<someLogicType<WidgetData>>({
  actions: {
    addNewWidget: (widgetKey: string, data: WidgetData) => ({
      widgetKey,
      data,
    }),
  },
  reducers: {
    widgets: [
      {} as { [key: string]: WidgetData }, 
      {
        addNewWidget: (state, { widgetKey, data }) => {
          return { ...state, [widgetKey]: data };
        },
      },
    ],
  },
  selectors: {
    widgetKeys: [
      (selectors) => [selectors.widgets],
      (widgets) => {
        return Object.keys(widgets);
      },
    ],
  },
});

In the above code, each key in the "widgets" reducer, represents one widget, and the value represents some data, that the widget uses (the same as the previous issue). The idea that i had, was to create a seperate keyed logic, that would allow the widgets to operate on their data. I was able to create some selectors that would allow to retrieve their data:

import { kea } from 'kea';

import { someLogic } from './someLogic';
import type { widgetLogicType } from './widgetLogicType';

export const widgetLogic = kea<widgetLogicType>({
  key: (props) => props.id,

  selectors: ({ props }) => ({
    widgetData: [
      () => [someLogic.selectors.widgets],
      (widgets) => {
        return widgets[props.id as number];
      },
    ],
  }),
});

But i'm having trouble with figuring out how to update the state from the connected logic. The only solution i found was to create reducers that would update the data in the logic that is containing it, and in the connected logic dispatch them through listeners. It would propably work, but it does not seem to be a clean solution, more a hack.
So the question is, are there some better ways to do this, or maybe some entirely different pattern that would allow me to have such functionality? Again thanks in advance, that was the last question for now :)

That's indeed the way I'd do it. Something as simple as this:

import { kea } from 'kea';

import { someLogic } from './someLogic';
import type { widgetLogicType } from './widgetLogicType';

export const widgetLogic = kea<widgetLogicType>({
  key: (props) => props.id,
  actions: {
    updateWidget: (changes: Partial<WidgetType>) => ({ changes }),
  },
  listeners: ({ props }) => {
    updateWidget: ({ changes }) => {
      someLogic.actions.updateWidgetByKey(props.id, changes)
    },
  },
  selectors: ({ props }) => ({
    widgetData: [
      () => [someLogic.selectors.widgets],
      (widgets) => {
        return widgets[props.id as number];
      },
    ],
  }),
});

I think it's not that much of a hack even. You basically abstract away one logic from another, making a clear boundary.

If there are actions or reducers you want to "copy through" from someLogic unchanged, feel free to use the connect explicit connections as well.

Thanks, so it seems i was on the right track.
Regarding the explicit connections, i don't think they will be able to help me in this situation, but thanks anyway 😃