{"action":"closed","number":105,"pull_request":{"url":"https://api.github.com/repos/james-proxy/james/pulls/105","id":58085542,"html_url":"https://github.com/james-proxy/james/pull/105","diff_url":"https://github.com/james-proxy/james/pull/105.diff","patch_url":"https://github.com/james-proxy/james/pull/105.patch","issue_url":"https://api.github.com/repos/james-proxy/james/issues/105","number":105,"state":"closed","locked":false,"title":"Breaking down components","user":{"login":"tomitm","id":4513759,"avatar_url":"https://avatars.githubusercontent.com/u/4513759?v=3","gravatar_id":"","url":"https://api.github.com/users/tomitm","html_url":"https://github.com/tomitm","followers_url":"https://api.github.com/users/tomitm/followers","following_url":"https://api.github.com/users/tomitm/following{/other_user}","gists_url":"https://api.github.com/users/tomitm/gists{/gist_id}","starred_url":"https://api.github.com/users/tomitm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tomitm/subscriptions","organizations_url":"https://api.github.com/users/tomitm/orgs","repos_url":"https://api.github.com/users/tomitm/repos","events_url":"https://api.github.com/users/tomitm/events{/privacy}","received_events_url":"https://api.github.com/users/tomitm/received_events","type":"User","site_admin":false},"body":"*So, this is kind of a big PR, sorry! Instead of 4-5 PRs, figured this would be a lot smoother with just one. The diff view doesn't look too clear, so have a look at the [folder view](https://github.com/tomitm/james/tree/components).*\r\n\r\n---\r\n\r\nOne thing I've noticed is that most components tried to do a lot during `render`. I've tried to break down the existing components into the smallest possible pieces. This should help with growth later and enable component reuse.\r\n\r\nAt the very bottom of React's [component docs](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions) (oddly enough), Facebook recommends using stateless components as a default, and then presumably the \"full\" components when you need to deal with state and things like `shouldComponentUpdate`.\r\n\r\n> In an ideal world, most of your components would be stateless functions because in the future we’ll also be able to make performance optimizations specific to these components by avoiding unnecessary checks and memory allocations. **This is the recommended pattern, when possible.**\r\n\r\nCouple of notes:\r\n- I've split components into folders, to make it easier to understand how the app is composed. I had to name the top-level files as `index.js` to be able to import the component by name, which results in being able to import `./component/main-content` instead of `./component/main-content/main-content.js`\r\n- Fixed the context menu behaviour; you were able to open it multiple times. Fixed this by moving that state out of `Request` up into `MainContent` where there's already state for `activeRequest`.\r\n  - Bonus that `Request` is state-free now, meaning 1 stateful `MainContent` instead of *n* stateful `Request`s, should make React pretty happy.\r\n  - Still kept `Request` as a \"full\" component for `shouldComponentUpdate`. Wondering what the cost to render `Request` is now that there isn't much logic in it.\r\n\r\nI made `Throttle` into a stateless component, but I'm a bit concerned, as that results in having to re-render everything, since there's a `data` object that contains application state outside of React's scope. React's docs do seem to suggest that rendering everything is okay (see [*A Note on Performance*](https://facebook.github.io/react/docs/multiple-components.html#a-note-on-performance)), but somehow that doesn't seem realistic to me.\r\n\r\nMight want to use a base `<App />` with [`setState`](https://facebook.github.io/react/docs/component-api.html) to manage `data` so that React knows to perform a shallow merge update of components without needing to call `render()`. Although, if that's at the top level, it's probably the same effect as right now, I imagine, so this might be moot.\r\n\r\nI'm also wondering if [Redux](http://redux.js.org/) would be worth exploring to help with this, or if you might find it overkill. Seems simpler than Facebook's own Flux, anyway. Still exploring options, as I'm still not 100% sure of the best React way to do this (my recent background has been in Angular).\r\n\r\n- [x] Break down components\r\n- [x] Organize into component folders\r\n- [x] Figure out main component import (index.js)","created_at":"2016-02-03T03:07:39Z","updated_at":"2016-02-10T09:20:01Z","closed_at":"2016-02-10T09:20:00Z","merged_at":"2016-02-10T09:20:00Z","merge_commit_sha":"66aa04ba97efb0c1bc05c2bc822af28219de2f74","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/james-proxy/james/pulls/105/commits","review_comments_url":"https://api.github.com/repos/james-proxy/james/pulls/105/comments","review_comment_url":"https://api.github.com/repos/james-proxy/james/pulls/comments{/number}","comments_url":"https://api.github.com/repos/james-proxy/james/issues/105/comments","statuses_url":"https://api.github.com/repos/james-proxy/james/statuses/4b3b287902598f3498911fba289aa34a3315800b","head":{"label":"tomitm:components","ref":"components","sha":"4b3b287902598f3498911fba289aa34a3315800b","user":{"login":"tomitm","id":4513759,"avatar_url":"https://avatars.githubusercontent.com/u/4513759?v=3","gravatar_id":"","url":"https://api.github.com/users/tomitm","html_url":"https://github.com/tomitm","followers_url":"https://api.github.com/users/tomitm/followers","following_url":"https://api.github.com/users/tomitm/following{/other_user}","gists_url":"https://api.github.com/users/tomitm/gists{/gist_id}","starred_url":"https://api.github.com/users/tomitm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tomitm/subscriptions","organizations_url":"https://api.github.com/users/tomitm/orgs","repos_url":"https://api.github.com/users/tomitm/repos","events_url":"https://api.github.com/users/tomitm/events{/privacy}","received_events_url":"https://api.github.com/users/tomitm/received_events","type":"User","site_admin":false},"repo":{"id":50808294,"name":"james","full_name":"tomitm/james","owner":{"login":"tomitm","id":4513759,"avatar_url":"https://avatars.githubusercontent.com/u/4513759?v=3","gravatar_id":"","url":"https://api.github.com/users/tomitm","html_url":"https://github.com/tomitm","followers_url":"https://api.github.com/users/tomitm/followers","following_url":"https://api.github.com/users/tomitm/following{/other_user}","gists_url":"https://api.github.com/users/tomitm/gists{/gist_id}","starred_url":"https://api.github.com/users/tomitm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tomitm/subscriptions","organizations_url":"https://api.github.com/users/tomitm/orgs","repos_url":"https://api.github.com/users/tomitm/repos","events_url":"https://api.github.com/users/tomitm/events{/privacy}","received_events_url":"https://api.github.com/users/tomitm/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/tomitm/james","description":"Web Debugging Proxy Application","fork":true,"url":"https://api.github.com/repos/tomitm/james","forks_url":"https://api.github.com/repos/tomitm/james/forks","keys_url":"https://api.github.com/repos/tomitm/james/keys{/key_id}","collaborators_url":"https://api.github.com/repos/tomitm/james/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/tomitm/james/teams","hooks_url":"https://api.github.com/repos/tomitm/james/hooks","issue_events_url":"https://api.github.com/repos/tomitm/james/issues/events{/number}","events_url":"https://api.github.com/repos/tomitm/james/events","assignees_url":"https://api.github.com/repos/tomitm/james/assignees{/user}","branches_url":"https://api.github.com/repos/tomitm/james/branches{/branch}","tags_url":"https://api.github.com/repos/tomitm/james/tags","blobs_url":"https://api.github.com/repos/tomitm/james/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/tomitm/james/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/tomitm/james/git/refs{/sha}","trees_url":"https://api.github.com/repos/tomitm/james/git/trees{/sha}","statuses_url":"https://api.github.com/repos/tomitm/james/statuses/{sha}","languages_url":"https://api.github.com/repos/tomitm/james/languages","stargazers_url":"https://api.github.com/repos/tomitm/james/stargazers","contributors_url":"https://api.github.com/repos/tomitm/james/contributors","subscribers_url":"https://api.github.com/repos/tomitm/james/subscribers","subscription_url":"https://api.github.com/repos/tomitm/james/subscription","commits_url":"https://api.github.com/repos/tomitm/james/commits{/sha}","git_commits_url":"https://api.github.com/repos/tomitm/james/git/commits{/sha}","comments_url":"https://api.github.com/repos/tomitm/james/comments{/number}","issue_comment_url":"https://api.github.com/repos/tomitm/james/issues/comments{/number}","contents_url":"https://api.github.com/repos/tomitm/james/contents/{+path}","compare_url":"https://api.github.com/repos/tomitm/james/compare/{base}...{head}","merges_url":"https://api.github.com/repos/tomitm/james/merges","archive_url":"https://api.github.com/repos/tomitm/james/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/tomitm/james/downloads","issues_url":"https://api.github.com/repos/tomitm/james/issues{/number}","pulls_url":"https://api.github.com/repos/tomitm/james/pulls{/number}","milestones_url":"https://api.github.com/repos/tomitm/james/milestones{/number}","notifications_url":"https://api.github.com/repos/tomitm/james/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/tomitm/james/labels{/name}","releases_url":"https://api.github.com/repos/tomitm/james/releases{/id}","deployments_url":"https://api.github.com/repos/tomitm/james/deployments","created_at":"2016-02-01T02:30:10Z","updated_at":"2016-02-01T02:30:11Z","pushed_at":"2016-02-09T20:46:02Z","git_url":"git://github.com/tomitm/james.git","ssh_url":"git@github.com:tomitm/james.git","clone_url":"https://github.com/tomitm/james.git","svn_url":"https://github.com/tomitm/james","homepage":"","size":2152,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"james-proxy:master","ref":"master","sha":"9a046b72186456d2d14e25e040a4f90c0dc13926","user":{"login":"james-proxy","id":16920662,"avatar_url":"https://avatars.githubusercontent.com/u/16920662?v=3","gravatar_id":"","url":"https://api.github.com/users/james-proxy","html_url":"https://github.com/james-proxy","followers_url":"https://api.github.com/users/james-proxy/followers","following_url":"https://api.github.com/users/james-proxy/following{/other_user}","gists_url":"https://api.github.com/users/james-proxy/gists{/gist_id}","starred_url":"https://api.github.com/users/james-proxy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/james-proxy/subscriptions","organizations_url":"https://api.github.com/users/james-proxy/orgs","repos_url":"https://api.github.com/users/james-proxy/repos","events_url":"https://api.github.com/users/james-proxy/events{/privacy}","received_events_url":"https://api.github.com/users/james-proxy/received_events","type":"Organization","site_admin":false},"repo":{"id":38034368,"name":"james","full_name":"james-proxy/james","owner":{"login":"james-proxy","id":16920662,"avatar_url":"https://avatars.githubusercontent.com/u/16920662?v=3","gravatar_id":"","url":"https://api.github.com/users/james-proxy","html_url":"https://github.com/james-proxy","followers_url":"https://api.github.com/users/james-proxy/followers","following_url":"https://api.github.com/users/james-proxy/following{/other_user}","gists_url":"https://api.github.com/users/james-proxy/gists{/gist_id}","starred_url":"https://api.github.com/users/james-proxy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/james-proxy/subscriptions","organizations_url":"https://api.github.com/users/james-proxy/orgs","repos_url":"https://api.github.com/users/james-proxy/repos","events_url":"https://api.github.com/users/james-proxy/events{/privacy}","received_events_url":"https://api.github.com/users/james-proxy/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/james-proxy/james","description":"Web Debugging Proxy Application","fork":false,"url":"https://api.github.com/repos/james-proxy/james","forks_url":"https://api.github.com/repos/james-proxy/james/forks","keys_url":"https://api.github.com/repos/james-proxy/james/keys{/key_id}","collaborators_url":"https://api.github.com/repos/james-proxy/james/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/james-proxy/james/teams","hooks_url":"https://api.github.com/repos/james-proxy/james/hooks","issue_events_url":"https://api.github.com/repos/james-proxy/james/issues/events{/number}","events_url":"https://api.github.com/repos/james-proxy/james/events","assignees_url":"https://api.github.com/repos/james-proxy/james/assignees{/user}","branches_url":"https://api.github.com/repos/james-proxy/james/branches{/branch}","tags_url":"https://api.github.com/repos/james-proxy/james/tags","blobs_url":"https://api.github.com/repos/james-proxy/james/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/james-proxy/james/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/james-proxy/james/git/refs{/sha}","trees_url":"https://api.github.com/repos/james-proxy/james/git/trees{/sha}","statuses_url":"https://api.github.com/repos/james-proxy/james/statuses/{sha}","languages_url":"https://api.github.com/repos/james-proxy/james/languages","stargazers_url":"https://api.github.com/repos/james-proxy/james/stargazers","contributors_url":"https://api.github.com/repos/james-proxy/james/contributors","subscribers_url":"https://api.github.com/repos/james-proxy/james/subscribers","subscription_url":"https://api.github.com/repos/james-proxy/james/subscription","commits_url":"https://api.github.com/repos/james-proxy/james/commits{/sha}","git_commits_url":"https://api.github.com/repos/james-proxy/james/git/commits{/sha}","comments_url":"https://api.github.com/repos/james-proxy/james/comments{/number}","issue_comment_url":"https://api.github.com/repos/james-proxy/james/issues/comments{/number}","contents_url":"https://api.github.com/repos/james-proxy/james/contents/{+path}","compare_url":"https://api.github.com/repos/james-proxy/james/compare/{base}...{head}","merges_url":"https://api.github.com/repos/james-proxy/james/merges","archive_url":"https://api.github.com/repos/james-proxy/james/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/james-proxy/james/downloads","issues_url":"https://api.github.com/repos/james-proxy/james/issues{/number}","pulls_url":"https://api.github.com/repos/james-proxy/james/pulls{/number}","milestones_url":"https://api.github.com/repos/james-proxy/james/milestones{/number}","notifications_url":"https://api.github.com/repos/james-proxy/james/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/james-proxy/james/labels{/name}","releases_url":"https://api.github.com/repos/james-proxy/james/releases{/id}","deployments_url":"https://api.github.com/repos/james-proxy/james/deployments","created_at":"2015-06-25T07:20:34Z","updated_at":"2016-02-09T14:28:55Z","pushed_at":"2016-02-10T09:20:00Z","git_url":"git://github.com/james-proxy/james.git","ssh_url":"git@github.com:james-proxy/james.git","clone_url":"https://github.com/james-proxy/james.git","svn_url":"https://github.com/james-proxy/james","homepage":"","size":2174,"stargazers_count":49,"watchers_count":49,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":7,"mirror_url":null,"open_issues_count":18,"forks":7,"open_issues":18,"watchers":49,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/james-proxy/james/pulls/105"},"html":{"href":"https://github.com/james-proxy/james/pull/105"},"issue":{"href":"https://api.github.com/repos/james-proxy/james/issues/105"},"comments":{"href":"https://api.github.com/repos/james-proxy/james/issues/105/comments"},"review_comments":{"href":"https://api.github.com/repos/james-proxy/james/pulls/105/comments"},"review_comment":{"href":"https://api.github.com/repos/james-proxy/james/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/james-proxy/james/pulls/105/commits"},"statuses":{"href":"https://api.github.com/repos/james-proxy/james/statuses/4b3b287902598f3498911fba289aa34a3315800b"}},"merged":true,"mergeable":null,"mergeable_state":"unknown","merged_by":{"login":"nerdbeere","id":423218,"avatar_url":"https://avatars.githubusercontent.com/u/423218?v=3","gravatar_id":"","url":"https://api.github.com/users/nerdbeere","html_url":"https://github.com/nerdbeere","followers_url":"https://api.github.com/users/nerdbeere/followers","following_url":"https://api.github.com/users/nerdbeere/following{/other_user}","gists_url":"https://api.github.com/users/nerdbeere/gists{/gist_id}","starred_url":"https://api.github.com/users/nerdbeere/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nerdbeere/subscriptions","organizations_url":"https://api.github.com/users/nerdbeere/orgs","repos_url":"https://api.github.com/users/nerdbeere/repos","events_url":"https://api.github.com/users/nerdbeere/events{/privacy}","received_events_url":"https://api.github.com/users/nerdbeere/received_events","type":"User","site_admin":false},"comments":7,"review_comments":14,"commits":5,"additions":596,"deletions":505,"changed_files":29}}