cycle-onionify icon indicating copy to clipboard operation
cycle-onionify copied to clipboard

Help needed - MemoryStream.map not producing output

Open ca057 opened this issue 6 years ago • 1 comments

Hey,

I hope this is the right place to ask for help. I'm currently trying to get started with CycleJS and cycle-onionify and have troubles getting my app to produce the right output. Currently it is a simple input field, on every enter a message object is created and should then be rendered in a list. With starting to split that into multiple, smaller components, I see no output of my message list anymore (only my input field). To be more specific: I can log the list of messages (which contain the correct amount of messages) and in my Message-component I also get a log output for the sources, so the code is at least touched (means: 2 messages in the list, 2 logs in my console; 3 when I add one more message and so on).

My Message-component looks like the following:

import xs from 'xstream';
import { div, p } from '@cycle/dom';
import isolate from '@cycle/isolate';

const calculateTimeString = timestamp => {
  const date = timestamp && new Date(timestamp);
  return `${date.toLocaleDateString()}: ${date.toLocaleTimeString()}`;
};

function Message(sources) {
  const state$ = sources.onion.state$;
  console.log(state$); // --> logs a MemoryStream

  const vdom$ = state$.map(state => {
    // HELPME this does not produce any output
    console.log('Message', state);
    return div('.messageItem', [
      p(calculateTimeString(state.time)),
      p(state.message),
    ]);
  });
  return {
    DOM: vdom$,
    onion: xs.empty(),
  };
}

// (sources) => ...
export default isolate(Message);

and is integrated into the following MessageList:

import { ul } from '@cycle/dom';
import isolate from '@cycle/isolate';
import { pick, mix } from 'cycle-onionify';
import xs from 'xstream';

import Message from './../Message';

function MessageList(sources) {
  const state$ = sources.onion.state$;

  const childrenSinks$ = state$.map(messages => {
    // --> with every new message, this logs me the array of messages [{...}, {...}, ...]
    console.log('MessageList', messages);
    return messages.map((msg, i) => {
      return isolate(Message, i)(sources);
    });
  });
  const vdom$ = childrenSinks$
    .compose(pick(sinks => sinks.DOM))
    .compose(mix(xs.combine))
    .map(ul);

  const reducer$ = childrenSinks$
    .compose(pick(sinks => sinks.onion))
    .compose(mix(xs.merge));

  return {
    DOM: vdom$,
    onion: reducer$,
  };
}

export default MessageList;

For the sake of completeness, everything is integrated into this main app:

import xs from 'xstream';
import { div, p, input } from '@cycle/dom';
import isolate from '@cycle/isolate';
import { prepend } from 'ramda';

// FIXME how to strcutre components? why not automatically importing index?
import MessageList from './components/MessageList/index';

function intent(domSource) {
  return domSource
    .select('.message')
    .events('keydown')
    .filter(({ keyCode, target }) => keyCode === 13 && target.value !== '')
    .map(ev => {
      const val = ev.target.value;
      // eslint-disable-next-line no-param-reassign
      ev.target.value = '';
      return {
        time: Date.now(),
        message: val,
      };
    });
}

function model(action$) {
  const initReducer$ = xs.of(() => ({ messages: [] }));
  const updateReducer$ = action$.map(message => prevState => ({
    messages: prepend(message, prevState.messages),
  }));
  return xs.merge(initReducer$, updateReducer$);
}

export default function App(sources) {
  const messageListSinks = isolate(MessageList, 'messages')(sources);

  const action$ = intent(sources.DOM);
  const parentReducer$ = model(action$);
  const messageListReducer$ = messageListSinks.onion;
  const reducer$ = xs.merge(parentReducer$, messageListReducer$);

  const vtree$ = messageListSinks.DOM.map(listNode =>
    div([
      p('Eingabe einer neuen Nachricht:'),
      input('.message', { attrs: { type: 'text', autofocus: true } }),
      listNode,
    ])
  );

  return {
    DOM: vtree$,
    onion: reducer$,
  };
}

Am I missing something? Am I doing something wrong? I tried to stick to the example here in the repo, but cannot find my error.

Hope one of you can help me out, in case you need more infos or the whole source-code, please let me know!

ca057 avatar Jul 26 '17 21:07 ca057

onion: xs.empty() may be a problem in Message?

stevenmathews avatar Oct 04 '17 20:10 stevenmathews