{"action":"created","issue":{"url":"https://api.github.com/repos/helpscout/brigade/issues/5","repository_url":"https://api.github.com/repos/helpscout/brigade","labels_url":"https://api.github.com/repos/helpscout/brigade/issues/5/labels{/name}","comments_url":"https://api.github.com/repos/helpscout/brigade/issues/5/comments","events_url":"https://api.github.com/repos/helpscout/brigade/issues/5/events","html_url":"https://github.com/helpscout/brigade/pull/5","id":386854606,"node_id":"MDExOlB1bGxSZXF1ZXN0MjM1NDc1ODAw","number":5,"title":"1.0 API Updates","user":{"login":"knicklabs","id":431654,"node_id":"MDQ6VXNlcjQzMTY1NA==","avatar_url":"https://avatars3.githubusercontent.com/u/431654?v=4","gravatar_id":"","url":"https://api.github.com/users/knicklabs","html_url":"https://github.com/knicklabs","followers_url":"https://api.github.com/users/knicklabs/followers","following_url":"https://api.github.com/users/knicklabs/following{/other_user}","gists_url":"https://api.github.com/users/knicklabs/gists{/gist_id}","starred_url":"https://api.github.com/users/knicklabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/knicklabs/subscriptions","organizations_url":"https://api.github.com/users/knicklabs/orgs","repos_url":"https://api.github.com/users/knicklabs/repos","events_url":"https://api.github.com/users/knicklabs/events{/privacy}","received_events_url":"https://api.github.com/users/knicklabs/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":2,"created_at":"2018-12-03T14:55:16Z","updated_at":"2018-12-03T19:20:28Z","closed_at":null,"author_association":"COLLABORATOR","pull_request":{"url":"https://api.github.com/repos/helpscout/brigade/pulls/5","html_url":"https://github.com/helpscout/brigade/pull/5","diff_url":"https://github.com/helpscout/brigade/pull/5.diff","patch_url":"https://github.com/helpscout/brigade/pull/5.patch"},"body":"In https://github.com/helpscout/brigade/pull/4 we added a `store` to the `EnhancedComponent` and we added a `connect` HOC.\r\n\r\nThe primary goal of this PR was to create a new API for Brigade that is more powerful and allows for a a state-based or store-based state management solution to be automatically implemented depending on the way that the new API is used.\r\n\r\nWe previously had an API like:\r\n\r\n```\r\ncomponents: {\r\n  '#component'() {\r\n    component: <Component model={this.model} />,\r\n    data: {\r\n      collection: this.collection,\r\n    },\r\n    selector: ({ collection }) => {\r\n      return collection.map(i => i.get('name')\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nThis had some limitations:\r\n\r\n1. The props on the component were static. Models or collections passed into props were not synced. \r\n2. The models and collections in data were synced and data was merged with props which was a somewhat confusing implementation. \r\n3. The selector function only operated on the keys in data. Again this was a somewhat confusing implementation. \r\n\r\nThe new API looks like this:\r\n\r\n```\r\ncomponents() {\r\n  return {\r\n    '#component': <Component collection={this.collection} model={this.model} />\r\n  }\r\n}\r\n```\r\n\r\n\r\nThis is much simpler and is the recommended way of using Brigade 1.0 for simple use cases. Collections and Models that are passed as props are now synced automatically. No need for the special `data` prop any more. \r\n\r\nUsing this approach, will result in waterfall props like what we experienced with Brigade pre-1.0. Because the component gets wrapped in an `EnhancedComponent` and the props get set as state on that enhanced component, they flow down to the component whenever they are changed. Any inner components need to receive those props via props as well. There is no way to connect to the state of `EnhancedComponent`. \r\n\r\nThis means we wind up passing props through our mounted component, which can be significant boilerplate if our mounted component is an App. \r\n\r\nIt just so happens we have a way of solving this now. Our new API can also take this shape:\r\n\r\n```\r\ncomponents() {\r\n  return {\r\n    '#component': Component,\r\n    initialState: {\r\n      collection: this.collection,\r\n      model: this.model,\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nWhen we set an initial state, the `EnhancedComponent` will use a `store` to keep the state and we can use the provided `connect` HOC to connect the store from any component. This means we no longer need to have waterfall props. Props do not need to be passed through every component because we can access the state directly from anywhere in our React app. Just like with props, collections and models are kept in sync. \r\n\r\nFor example, we can do something like this:\r\n\r\n```\r\nimport { connect } from 'brigade'\r\nconst mapStateToProps = ({ todos }) => ({ todos })\r\nexport default connect(mapStateToProps)(TodoList)\r\n```\r\n\r\nNow our todo list will receive `todos` as props. Just like Redux. \r\n\r\nWe can also use `externalActions` to be able to access actions defined outside our React app, from anywhere inside our React app without having to pass them through as props as well. \r\n\r\n```\r\ncomponents() {\r\n  return {\r\n    '#component': Component,\r\n    initialState: {\r\n      collection: this.collection,\r\n      model: this.model,\r\n    },\r\n    externalActions: {\r\n      addTodo: this.addTodo,\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nHere's how we pass that `addTodo` action in as prop on any component in our React app. \r\n\r\n```\r\nconst actions = store => store.getExternalActions()\r\nexport default connect(null, actions)(TodoForm)\r\n```\r\n\r\nThis PR also adds a Storybook to make working on this library easier. It is a also a good reference for ways to use this library. Even better for that though, this PR also adds Docs. \r\n\r\nFinally, this PR removes the `selector` feature. Because we have a more Redux-like API, we no longer need this feature. You can bring your own `select` library if needed."},"comment":{"url":"https://api.github.com/repos/helpscout/brigade/issues/comments/443835382","html_url":"https://github.com/helpscout/brigade/pull/5#issuecomment-443835382","issue_url":"https://api.github.com/repos/helpscout/brigade/issues/5","id":443835382,"node_id":"MDEyOklzc3VlQ29tbWVudDQ0MzgzNTM4Mg==","user":{"login":"coveralls","id":2354108,"node_id":"MDQ6VXNlcjIzNTQxMDg=","avatar_url":"https://avatars1.githubusercontent.com/u/2354108?v=4","gravatar_id":"","url":"https://api.github.com/users/coveralls","html_url":"https://github.com/coveralls","followers_url":"https://api.github.com/users/coveralls/followers","following_url":"https://api.github.com/users/coveralls/following{/other_user}","gists_url":"https://api.github.com/users/coveralls/gists{/gist_id}","starred_url":"https://api.github.com/users/coveralls/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/coveralls/subscriptions","organizations_url":"https://api.github.com/users/coveralls/orgs","repos_url":"https://api.github.com/users/coveralls/repos","events_url":"https://api.github.com/users/coveralls/events{/privacy}","received_events_url":"https://api.github.com/users/coveralls/received_events","type":"User","site_admin":false},"created_at":"2018-12-03T19:20:28Z","updated_at":"2018-12-03T19:20:28Z","author_association":"NONE","body":"## Pull Request Test Coverage Report for [Build 74](https://coveralls.io/builds/20426099)\n\n* **46** of **46**   **(100.0%)**  changed or added relevant lines in **8** files are covered.\n* No unchanged relevant lines lost coverage.\n* Overall coverage remained the same at **100.0%**\n\n---\n\n\n\n|  Totals | [![Coverage Status](https://coveralls.io/builds/20426099/badge)](https://coveralls.io/builds/20426099) |\n| :-- | --: |\n| Change from base [Build 50](https://coveralls.io/builds/20183825): |  0.0% |\n| Covered Lines: | 144 |\n| Relevant Lines: | 144 |\n\n---\n##### 💛  - [Coveralls](https://coveralls.io)\n"}}
{"actor":{"display_login":"coveralls"}}