salsita / prism

React / Redux action composition made simple http://salsita.github.io/prism/
495 stars 24 forks source link

Getting component path string #42

Closed jmarceli closed 8 years ago

jmarceli commented 8 years ago

Get it directly from action wrap parameter example below

-- ORIGINAL QUESTION Hi, Is it somehow possible to get component path described by action type inside that component view? It will be very helpful for naming forms in redux-form (ensuring unique name).

Example: Application state structure: root -> orders -> order Actions dispatched from order has type of: `Orders.Order.*'

Is it possible to generate Orders.Order string inside Order component view? I didn't find any way of "extracting" that component path from dispatch method.

tomkis commented 8 years ago

Would you just need to store it in the Model?

jmarceli commented 8 years ago

As for now I'm wrapping reduxForm() inside stateless function which gives me possibility to provide initial values based on redux-elm component model. Still I have no idea how to provide unique value for form key. Here is how it looks like:

const OrderFormWrapper = props => {
  const { dispatch, model } = props;
  // here both `dispatch` and `model` redux-elm props are available
  // but I have no idea how to "get" the component "path" like `Orders.Order`
  // if I will be able to get this path I would use it as a value for the `form` key below

  const Form = reduxForm({
    initialValues: model2form(model), // <-- converts model values to form fields
    form: 'order', // <-- this should have unique value in case I want to create more than one order form
    fields: ['id', 'code', 'status'],
  })(OrderForm); // <-- OrderForm is an actual form component which needs to be wrapped by reduxForm

  return (
    <Form {...props} />
  );
};
tomkis commented 8 years ago

One option would be storing the information in the app state because every action (you'd use Mount here) holds action prefix

jmarceli commented 8 years ago

Thanks. I think that solves my issue. For future reference here is the example code: Updater

export const init = () => ({
  path: '', // here will be the path after component mounts
  // ... rest of the model initialization code
});

export default new Updater(init(), saga)
  .case('@@redux-elm/Mount', (model, { wrap }) => {
    // wrap variable has component path (with trailing dot) e.g. 'OrdersPage.Order.'
    // you may get rid of the dot with regex e.g. wrap.replace(/\.$/, '')
    return { ...model, path: wrap };
  })
  // ... other actions handled by this component
  .toReducer();

Form

const OrderFormWrapper = props => {
  const { model } = props;

  const Form = reduxForm({
    initialValues: model2form(model), // <-- converts model values to form fields (irrelevant in this example)
    form: model.path,
    fields: ['id', 'code', 'status'],
  })(OrderForm); // <-- OrderForm is an actual form component which needs to be wrapped by reduxForm

  return (
    <Form {...props} />
  );
};

It is worth to mention that because of possible dots in model.path your form may be treated by redux-form as nested form. Which shouldn't matter but it's better to know that. Of course simple .replace('.', '_') on the model.path variable can fix/change that.

Here is how your state may look if your model.path is OrdersPage.Order: image