Giter VIP home page Giter VIP logo

coflux's People

Contributors

blainekasten avatar ppoulsen avatar thelarkinn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

coflux's Issues

rename `mapStateToProps`

Technically this project isn't using any specific RxJS. Though the way things work, it feels like each component observes state when it changes. I'm wondering if observeState would help describe what components are doing better, and sort of make a clearer seperation from redux.

wrap(Comp, {
  observeState() {
    return {
      foo: 'bar.baz'
    };
  },

  actions: {
    ...
  },
});

thoughts?

Look into decorator syntax

I'm curious if we could just have the values live in the react class. Not sure how this would play with stateless components (which we're aiming to support).

Imagining this:

class

@coflux
class Foo extends Component {
  render() {
  }

  mapStateToProps() {
  }

  static actions = {
    foobar() { }
  }
}

statelss

const actions = {};

@coflux(
  mapStateToProps() {},
  actions
)
function Foo() {
}

Nested `wraps` fail `shouldComponentUpdate`

Their needs to be some reverse crawling to dictate if child components would need a shouldComponentUpdate call.

The current issue is this. Assume all components wrap to different data.

wrap(A, { userId: 'user.id' });
wrap(B, { firstName: 'user.firstName' });
wrap(C, { userId: 'user.id' });

Given this, if it is rendered in the following structure:

  A
 / \
B   C

If user.id was changed, A would re-render, B wouldn't, and C would.

BUT.

if user.firstName changed. Nothing would get updated correctly.

That's wrong. We should find a way to track it's internal dependency in reverse up the tree. So given the above, at runtime it effectively internally changes to:

wrap(A, { userId: 'user.id', firstName: 'user.firstName' })

BabelPlugin for masking `_` prop api.

The idea here is that https://github.com/blainekasten/coflux/tree/master/docs#mapped-props-with-_ is an awkward API that could be auto-generated by a babel transform.

The _ is a perf gain because components sometimes can modify data they aren't rendering. For example a component with a delete all button isn't likely rendering anything based on state, but clicking it will empty an array.

e.g.,

function DeleteAll({actions}) {
  return <button onClick={actions.deleteAll}>Delete All</button>;
}

wrap(DeleteAll, {
  mapStateToProps() {
    return {
      emailList: 'app.user.emails';
    };
  },

  actions: {
    deleteAll({emailList}, next) {
      next({emailList: null});
      /*
       * We need to know about emailList so we can modify it
       * But we dont' need to re-render if the list changes,
       * because we aren't rendering it.
       */
    }
  }
});

So we have this perf optimization (that could change, but for now it works) that a mapped prop prefixed with _ is marked as write-only. Meaning it doesn't read from it, and doesn't care if the value changes.

While this makes sense, it'd be best if we could have a babel transform, that could read the components render function, and determine what props are write-only and autoprefix the keys with _.

DevTooling

In order to successfully make a flux library today, it needs all the bells and whistles. coflux should ship with a good set of devtools to make debugging simpler.

Support Middleware

Talking with @developerdizzle. We talked about middlewares and the general ideas. Here are some thoughts as a take away.

Middleware might be needed

Legimiate cases for middleware are:

  • history (undo/redo)
  • logging
  • Devtools

I think there are 2 ways we could approach this. actionExtender's or generic middleware.

This is how I would expect them to be implemented:

actionExtender
// happens at some top level
const history = [];
actionExtender('undoable', function(prevState, proposedState, componentName, actionName) {
  // do something with the previous or proposed state
  history.push(prevState);
});
function foo({actions}) {
  return <input onClick={actions.handleClick.undoable} /> // undoable being the key here
}

wrap(foo, { actions: {
  handleClick(state, next) {
    // does something
    next({foo: 'bar'});
  }
}});

Pro's here are actions can opt into using a middleware. This technically isn't middleware but it might support all the use-cases we need.

middleware

This is true middleware, every action called also calls the middleware's.

// some top level file
middleware(function logger(prevState, proposedState, componentName, actionName) {
  fetch('api/v2/log', {prevState, proposedState, componentName, actionName});
});

Other notes

The implementation of this should probably live on Provider. Something like this:

render(
  <Provider middlewares={[logger, devTools]}>
    ...
  </Provider>
)

BabelPlugin for infering store structure.

MVP requires a property of store on Provider. I dream of a day where a Babel Transform can assume all of the store's structure for you so you don't have to map these things. By observing the relationship of components to state, I think it should be inferable.

API for default state?

This is an unknown, but if the state is not needed as a default argument, there has to be a way to set the default state. Initial thoughts are a callback of a sort.

<Provider defaultState={() => { foo: 'bar', x: true }} />

Knowing store shape benefits

If we can probably infer the store shape, we can also then do a propType type thing to make sure updatedState doesn't break the shape. For example:

If we know that state.x is an array, and somebody's action tries to set it to a string, then the store API is broken.

// state.nicknames = ['joe', 'james', 'john'];

// action
updateNickname({nickname}, next) {
  next({nickname: 'jacked up joe'});
});

This should throw an error because the state is inferred to be an array from either some default data, or through introspection of other components.

Blessed Lists support?

This is the biggest limitation i've found thus far:

Lists.

Due to implementation things, it's hard for a ListItem component to bind to it's index in the store. So they can't ever be wrapped. Is that actually a problem? Is it fine if the List itself is wrapped and just passes props the normal way? The hard part there is that the ListItem can't update state without passing actions created in the List.

Here is the only way to create a list right now:

function List({items, actions}) {
  return (
    <div>
      {items.map(
        (item, i) => <ListItem {...item} updateItem={actions.updateItem.bind(null, i)} />
      }
    </div>
  );
}

wrap(List, {
  mapStateToProps() {...},
  actions: { updateItem() {...} },
});

function ListItem({details, updateItem}) {
  return (
   <div onClick={updateItem}>{details}</div>
  );
}

This is how I dream we could make it:

function List({items, actions}) {
  return (
    <div>
      {items.map(
        (item, i) => <ListItem {...item} index={i} />
      }
    </div>
  );
}

wrap(List, {
  mapStateToProps() {
    return { items: 'items' };
  }
});

function ListItem({details, updateItem}) {
  return (
   <div onClick={updateItem}>{details}</div>
  );
}

wrap(List, {
  mapStateToProps(index) {
    return {
      details: `items[${index}].details`,
    };
  },
  actions: { updateItem() {...} },
});

Feedback

Looking for feedback on this library.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.