Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Displaying Flux actions #24

Open
pekala opened this issue Jul 6, 2015 · 9 comments
Open

Displaying Flux actions #24

pekala opened this issue Jul 6, 2015 · 9 comments

Comments

@pekala
Copy link
Contributor

pekala commented Jul 6, 2015

If your components are strictly props-based and change their state by emitting Flux actions, the usefulness of the playground is somewhat limited.

What if it was possible to display actions (name and payload) emitted by the component in real time?

There are many implementations of Flux, so it would be required to provide a hook to somehow proxy from specific implementation to a common format used for displaying the actions.

What do you think?

@ovidiuch
Copy link
Owner

ovidiuch commented Jul 7, 2015

What if it was possible to display actions (name and payload) emitted by the component in real time?

This sounds cool, similar to what @gaearon did in this ReactEurope talk, but it might be a complementary tool to the ComponentPlayground. Maybe relevant for the Cosmos "suite", but not sure if merging them is a good design direction.

There are many implementations of Flux, [...]

This is exactly my concern. Flux frameworks move fast and in many directions, and I want to avoid creating a too opinionated and feature-rich tool to begin with, since it will might lose its quality/flexibility in time.

It's still a real problem, though, as a lot of React users use Flux. Here's an alternative: At work we go one level lower and mock XHR requests. It's not part of Cosmos, but it's pretty easy to set up and if it sounds interesting I can share our solution and see how we can make it available for other Cosmos/ComponentPlayground users as well.

@gaearon
Copy link

gaearon commented Jul 7, 2015

I'd say ComponentPlayground is awesome for “dumb” components.

I agree trying to shoehorn Flux into it is trying to do too much.
Better to use Flux implementation that already allows these kinds of tools, like in my talk.

@pekala
Copy link
Contributor Author

pekala commented Jul 8, 2015

@gaearon Seen the talk live, awesome sauce :) But it's not viable to everyone to switch to Redux or something as powerful right away.

Taking a step back, if we treat such a dumb component as a black box, we can already see what goes in (fixtures) and it would be really nice to express what goes out of it. It doesn't have to be Flux actions, could be just calls to callback functions.
One way I see this could be implemented is to expose (from playground or Cosmos) a very simple hook for logging things out to a component displaying a simple list. Then it should be possible to create pluggable adapters to whatever your convention of outside communication from your component is. There could be an adapter for Redux/Reflux/etc. that would mock actions or you could just log something from callbacks provided in fixtures.
I agree that the code here should be kept as simple and general as possible, but it would be nice to enable this kind of powerful plugins.

As for the XHR, I think this might be a bit too far from the component itself. Or, if you have a component that does some Ajax calls, it could use an adapter to present them in the log.

@ovidiuch
Copy link
Owner

ovidiuch commented Jul 8, 2015

it would be really nice to express what goes out of it. It doesn't have to be Flux actions, could be just calls to callback functions.

Interesting idea, seeing what goes out.

The prop functions can be pretty easily logged because they are also part of the fixture and you can attach any sort of functions you want (wrappers around console.log, etc).

@pekala
Copy link
Contributor Author

pekala commented Jul 9, 2015

It could be an second component, mounted by Cosmos that exposes a global function, say cosmosLog, and renders all calls to it nicely formatted in a foldable sidebar.

Then for the fixtures we could make it easy to pass a stubbed callback function that internally uses this cosmosLog function and dumps arguments it was called with. Or if you need a more fine grain control over what's displayed, you can build your own stub using cosmosLog function.

And if you use Flux in your components you should be able to stub as well. For example for Reflux I would stub the Actions object and cosmosLog all the calls on its methods with method name and arguments. We could provide these adapters for some popular Flux libraries as plugins or just explain how to write it.

@pekala
Copy link
Contributor Author

pekala commented Jul 14, 2015

I made a simple proof of concept which, in my opinion, works fairly well. Here is the gist of it:

  1. Exposing a global function from component playground's componentDidMount:
window.playgroundLog = function(log) {
  var logs = _.clone(this.state.logs);
  logs.push({
    message: log,
    time: moment()
  });

  this.setState({
    logs: logs
  });
}.bind(this);
  1. Simple sidebar that prints outs this.state.log in readable form, not that interesting
  2. Stubs injected, for example using webpack config hook. Example for Flux:
var AppDispatcher = require('./AppDispatcher');
AppDispatcher.dispatch = function(payload) {
    window.playgroundLog('AppDispatcher.dispatch called with '+ JSON.stringify(payload));
}

and for Reflux:

var actions = require('./actions');
for (var method in actions) {
    if (actions.hasOwnProperty(method) && typeof(actions[method]) === 'function') {
        actions[method] = function(payload) {
            var message = 'Action '+ method +' called';
            if(payload) {
                message += ' with ' + JSON.stringify(payload);
            }
            window.playgroundLog(message);
        }
    }
}

so in logger we would get messages like Action buttonClicked called with {foo: 10} or AppDispatcher.dispatch called with {"actionType":"click"} (the messages can obviously be made nicer). What do you think?

@gaearon
Copy link

gaearon commented Jul 14, 2015

Shameless plug: I just released time traveley Redux DevTools.
Maybe even if you don't use it, you'll steal some (or suggest!) some ideas.

@ovidiuch
Copy link
Owner

I made a simple proof of concept which, in my opinion, works fairly well. Here is the gist of it:

I like the flow, and that you thought of stubbing Flux implementation as well. But since I'm a minimalist, I propose the following solution for the MVP:

Use the browser console for output and have a small log generator lib inside Cosmos (would work great with #25 (comment)).

E.g.

// Inside a fixture file
var consoleLogger = require('cosmos-js/logger/console');

module.exports = {
  fooProp: 'bar',
  onSelect: consoleLogger('onSelect')
};

Which would simple look like:

module.exports = function(callbackName) {
  return function(a, b, c, d, e, f) {
    console.log.call(null, 'Called "' + callbackName + '" callback with', a, b, c, d, e, f);
  };
}

I'm thinking this has 80% of the value with 20% the effort, since building a component has its overhead. Also, not stringifying might be an advantage because the browse console lets you expand any data structure in place (though the data will be a bit misleading if mutated since the log, so we might choose to stringify anyway).

Of course, later down the road we can add pluggable loggers and offer a pretty one as well. Even better, why not extract @gaearon's LogMonitor component from the redux-devtools repo and include it in both places by following some generic interface.

What do you think?

cc @NiGhTTraX you might be interested in this thread

PS. @gaearon congrats for open sourcing the dev tools!

@pekala
Copy link
Contributor Author

pekala commented Jul 17, 2015

I dig the idea! I should have some time next week to tinker with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants