Coder Social home page Coder Social logo

Comments (6)

smalluban avatar smalluban commented on September 23, 2024

In the hybrids, you don't need a state or props thing. All your properties are available in other properties (when set as a getter, including render method). The hybrids descriptors object is a flat key -> value map. If you want to connect more data from a redux store, you should call connect for each of them:

const Component = {
  myReducer: connect(store, state => state.myReducer), // it should be 'state' not 'store' as you wrote
  myOtherThing: connect(store, state => state.myOtherThing),
  // usage of the data from redux store
  mergedThings: ({ myReducer, myOtherThing }) => myReducer + myOtherThing, 
}

The main concept of the library is to have independent properties, each of them are defined separately and can be a redux store value, simple property mapped from an attribute or something more complex as a children or parent factory.

However, if you really want a props property, you can do something like this:

const Component = {
  props: connect(store, ({ myReducer, myOtherThing } ) => ({ myReducer, myOtherThing })),
  mergedThings: ({ props }) => props.myReducer + props.myOtherThing, 
}

The above example uses destructuring (takes two properties from store state) and returns object with this two props.

from hybrids.

DavideCarvalho avatar DavideCarvalho commented on September 23, 2024

Oh okay, i just wanted to know if it was intended or maybe something that passed through. I wanted to make something like react-redux binding, something that I could say to the component what reducers I need and put only these.
The workaround was to put getState() directly on the props, it worked, but the props now has more than the component need. Well, at least it's working, I can keep up with the rest of my stuff while I think in a more descent way. Maybe make this mergedThings stuff inside of the redux binding I've made for hybrids.

from hybrids.

smalluban avatar smalluban commented on September 23, 2024

I supposed, that you have used connect factory function from an example with a redux counter. If you would use this:

// This is a factory for connecting redux store.
// It can be taken out from here and use in other elements.
const connect = (store, mapState) => ({
  get: mapState ? () => mapState(store.getState()) : () => store.getState(),
  connect: (host, key, invalidate) => store.subscribe(invalidate),
});

It is very flexible what you return in the function from the second argument(mapState). It works pretty the same as it works in react-redux. It can map whole current state of the redux store into anything you need - an object with props, simple value, or something calculated from state.

I still don't understand what you mean by the reducers. Reducer is a function which creates a new state of the store by dispatching an action, it is not a data that you want to connect to the component.

from hybrids.

DavideCarvalho avatar DavideCarvalho commented on September 23, 2024

What I wanted was the possibility of having inner properties inside my "props", this way, my actions and states would be inside it, just like redux do.

export const connectComponent = (
  reduxStore,
  reduxStoreDictionary = {},
  actionsDictionary = {},
  component,
) => {
  let componentWithProps = { ...component, props: connect(reduxStore) };
  Object.keys(actionsDictionary).forEach((actionPropertyName) => {
    componentWithProps = {
      ...componentWithProps,
      actions: {
        ...componentWithProps.actions,
        [actionPropertyName]: actionsDictionary[actionPropertyName],
      },
    };
  });
  return componentWithProps;
};

As you can see, I'm using connect method to put the whole app state inside the props, but if I have 5 different reducers and the component only needs 2, it will get everything.

I tried something like this:

- let componentWithProps = { ...component, props: connect(reduxStore) };
+ let componentWithProps = component;
+ Object.keys(reduxStoreDictionary).forEach((reducerPropertyName) => {
+     componentWithProps = {
+       ...componentWithProps,
+       props: {
+         ...componentWithProps.props,
+        [reduxStoreDictionary[reducerPropertyName]]: connect(reduxStore, state => state[reducerPropertyName]),
+      },
+    };
+  });

This way, I would get only the needed state for the component, but this don't work.

from hybrids.

smalluban avatar smalluban commented on September 23, 2024

It won't work because the component definition is a flat key -> descriptor map. The library goes to your props or actions and checks if this object has get or set method at least to interpret it as a property definition. Otherwise it uses translation, and in this case, it will wrap your object (with actions or props) with property factory.

You can not create nested properties inside of the object value. It is not supported and I think not really useful. How you can deal with it? Let's go with your two problems separately.

The props problem. I think this can be handled by my proposal in my first comment. You can map your redux state in any way to create getter property (which will be updated any time when the state changes):

{
  props: connect(reduxStore, (state) => {
     // your manipulation code
     return { one: state.one, two: state.two + state.three };
  }),
  render: ({ props }) => html`
     <div>${props.one} ${props.two}</div>
  `,
}

The actions problem. In your last code example, you are passing actions from actionDictionary, so I don't know if the are just action creators and the return plain object with action type and payload, or the are already bind to the store instance. Regardless of what you pass, I think you don't need it at all. It would be much clearer if you use your actions directly in the component definition, like this:

import myStore, { connect } from './myReduxStore';
import { someAction } from './reduxActions';

export default {
  props: connect(myStore, (state) => {...}),
  render: ({ props: { param1, param2 } }) => html`
    <my-element oncustomevent="${() => myStore.dispatch(someAction(param1, param2))">
        ....
    </my-element>
  `,
}

The main concept of the library is to have clear data sources in properties, and external functions for all side effects, which are connected to the component by the events in render method or connect or other places of the properties definition.

If () => myStore.dispatch(someAction) is too verbose for you, you can also create little helper over your store instance and export it form file where you setup store:

// myReduxStore.js
import createStore from 'redux';
...
const reduxStore = ....;

export default reduxStore;
export const dispatch = (action) => () => reduxStore.dispatch(action);

// myComponent.js
import { dispatch } from './myReduxStore';
import { someAction } from './reduxActions';

{
  render: ({ props: { param1, param2 } }) => html`
    <my-element oncustomevent="${() => dispatch(someAction(param1, param2))}">
    ...
  `,
}

At last but not least, if you want to make this action your public API of the component, you can also use that function in property getter, and call that property in render method:

{
  // Here is a function chain, because the first function is a getter, so it is called when you want
  // a property value, and that property should return agian a function, which will be called
  // when event of <my-element> occur.
  someAction: ({ props: { param1, param2 } }) => () => dispatch(someAction(param1, param2)),
  render: ({ someAction }) => html`
    <my-element oncustomevent="${someAction}">
    ...
  `,
}

All the above examples assume, that parameters to your action creator are taken from the component properties (it can be your props, but also any other defined properties).

EDIT:
If you really want to have all your actions available as a actions property, it also possible:

import { connect } from './connect';

export function connectComponent(store, actionsDictionary = {}, component) {
  return {
     ...component,
     props: connect(store),
     actions: () => Object.keys(actionsDictionary).reduce((acc, key) => ({ 
       ...acc, 
       [key]: (...args) => store.dispatch(actionsDictionary[key](...args)),
     }, {}),
  };
}

Using this pattern, you have props with the redux state, and actions as an object with keys as a bind action, which dispatches to the connected redux store.

from hybrids.

smalluban avatar smalluban commented on September 23, 2024

I'm closing now. If you would have other issues with connecting to redux feel free to reopen.

from hybrids.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.