JSFiddle - React, Tailwind, and code Playground

HTML

<script src="http://cdn.ractivejs.org/edge/ractive.js"></script>
<script src="https://rawgit.com/ractivejs/ractive-transitions-slide/master/dist/ractive-transitions-slide.js"></script>
<main></main>

<script id='template' type='text/ractive'>
    <p>Switch between the two streams:</p>

    <button on-click='select:stream_id1'>select stream_id1</button>
    <button on-click='select:stream_id2'>select stream_id2</button>
    
    <p>Trigger a merge, but only if stream_id1 is selected:</p>
    
    <button on-click='updateStream:stream_id1'>update stream_id1</button>
    
    {{#current_messages}}
    {{>render_message_stream}}
    {{/current_messages}}
</script>

<script id='render_message_stream' type='text/ractive'>
    <p>Message stream:</p>
    
    {{#current_message_stream}}
    <div class="stream">
        {{>render_message}}
    </div>
    {{/current_message_stream}}
</script>

<script id='render_message' type='text/ractive'>
    <div class="message" intro-outro="slide:slow">
        {{message}}
    </div>
</script>

JavaScript

ractive = new Ractive({
    el: 'main',
    template: '#template',
    data: {
        messages: {
			stream_id1: {
				some_stream_metadata: 'foo',
				stream: [
					{id: 'someid1', message: 'message1'},
					{id: 'someid2', message: 'message2'}
				]
			},
			stream_id2: {
				some_stream_metadata: 'bar',
				stream: [
					{id: 'someid3', message: 'message3'},
					{id: 'someid4', message: 'message4'}
				]
			}
		},
        current_stream_id: 'stream_id1'
    }
});

ractive.on({
    select: function ( event, id ) {
        this.set( 'current_stream_id', id );
    },
    updateStream: function ( event, id ) {
        this.set( 'messages.' + id + '.stream', getRandomStream() );
    }
});

ractive.observe( 'current_stream_id', function ( id ) {
    var current_messages = this.get( 'messages.' + id );
    
    this.set( 'current_messages', current_messages );
    
    this.set( 'current_message_stream', null, function () {
        this.set( 'current_message_stream', current_messages.stream );
    });
});

ractive.observe( 'messages.*.stream', function ( new_stream, old_stream, keypath ) {
    var id_of_changed_stream = /messages\.([^\.]+)\.stream/.exec( keypath )[1];
    
    if ( id_of_changed_stream === this.get( 'current_stream_id' ) ) {
        this.merge( 'current_message_stream', new_stream, {
            compare: function ( item ) {
                return item.id;
            }
        });
    }
});

function getRandomStream () {
    var stream = [], length = Math.ceil( Math.random() * 5 ), id, usedIds = {};
    
    while ( length-- ) {
        do {
            id = Math.ceil( Math.random() * 5 );
        } while ( usedIds[id] );
        
        usedIds[id] = true;
        
        stream.push({
            id: 'someid' + id,
            message: 'message' + id
        });
    }
    
    return stream;
}