salsita / prism

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

Dynamic component composition #46

Closed biirus closed 7 years ago

biirus commented 7 years ago

Hi, there!

Maybe I have a very stupid question but I can't understand how to make multiple components composition when the list of components is dynamically changes. For example I have two components:

Component it's view:

export default view(({ model, dispatch }) => (
    <div onClick={() => dispatch({type: 'CLICK', payload: model.content}>
        {model.content}
    </div>
))

ComponentList is's view:

export default view(({ model, dispatch }) => (
    <ul>
        <li>
            <Component model={{content: model.a}} dispatch={forwardTo(dispatch, 'A')} />
        </li>
        <li>
            <Component model={{content: model.b}} dispatch={forwardTo(dispatch, 'B')} />
        </li>
    </ul>
))

it's updater:

export default new Updater({a: null, b: null})
    .case('A', (model, action) => {...model, a: ComponentUpdater(model.a, action)}
    .case('B', (model, action) => {...model, b: ComponentUpdater(model.b, action)}
    .toReducer();

It is totally clear for me. But what should I do, if I have dynamically changed component list. Eg:

export default view(({ model, dispatch }) => (
    <ul>
        {model.list.map((item, index) => 
            <li>
                <Component model={{content: item}} dispatch={forwardTo(dispatch, index)} />
            </li>
        )}       
    </ul>
))

How should my ComponentList updater look like?

tomkis commented 7 years ago

Hello, you'd need to use parametirezedMatcher there's an entire chapter in documentation which covers exactly your use case.

Something like:

// view
export default view(({ model, dispatch }) => (
    <ul>
        {model.list.map((item, index) => 
            <li>
                <Component model={{content: item}} dispatch={forwardTo(dispatch, 'Component', index)} />
            </li>
        )}       
    </ul>
));

// updater
import { Updater, Matchers } from 'redux-elm';

export default new Updater({ components: [] })
  .case('Component', (model, action) => {
    const numericComponentIndex = parseInt(action.matching.args.param, 10);

    return {
      ...model,
      components: model.components.map((componentModel, index) => {
        if (index === numericComponentIndex) {
          return componentUpdater(componentModel, action);
        } else {
          return componentModel;
        }
      })
    };
  }, Matchers.parameterizedMatcher)
biirus commented 7 years ago

Thanks, @tomkis1! My bad =(

tomkis commented 7 years ago

np!