{"action":"created","issue":{"url":"https://api.github.com/repos/babel-plugins/babel-plugin-incremental-dom/issues/8","labels_url":"https://api.github.com/repos/babel-plugins/babel-plugin-incremental-dom/issues/8/labels{/name}","comments_url":"https://api.github.com/repos/babel-plugins/babel-plugin-incremental-dom/issues/8/comments","events_url":"https://api.github.com/repos/babel-plugins/babel-plugin-incremental-dom/issues/8/events","html_url":"https://github.com/babel-plugins/babel-plugin-incremental-dom/issues/8","id":97584668,"number":8,"title":"{Child AssignmentExpressions}","user":{"login":"thejameskyle","id":952783,"avatar_url":"https://avatars.githubusercontent.com/u/952783?v=3","gravatar_id":"","url":"https://api.github.com/users/thejameskyle","html_url":"https://github.com/thejameskyle","followers_url":"https://api.github.com/users/thejameskyle/followers","following_url":"https://api.github.com/users/thejameskyle/following{/other_user}","gists_url":"https://api.github.com/users/thejameskyle/gists{/gist_id}","starred_url":"https://api.github.com/users/thejameskyle/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thejameskyle/subscriptions","organizations_url":"https://api.github.com/users/thejameskyle/orgs","repos_url":"https://api.github.com/users/thejameskyle/repos","events_url":"https://api.github.com/users/thejameskyle/events{/privacy}","received_events_url":"https://api.github.com/users/thejameskyle/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/babel-plugins/babel-plugin-incremental-dom/labels/enhancement","name":"enhancement","color":"84b6eb"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":13,"created_at":"2015-07-28T00:22:41Z","updated_at":"2015-08-01T04:36:45Z","closed_at":null,"body":"Originally raised in #5 ([start here](https://github.com/babel-plugins/babel-plugin-incremental-dom/pull/5#issuecomment-124945873))\r\n\r\n### Issue\r\n\r\nSimply put, there is no direct translation for the following in iDOM:\r\n\r\n```js\r\nlet foo = <span>foo</span>;\r\n\r\n<div>{foo}</div>\r\n```\r\n\r\nThe output would currently result in:\r\n\r\n```js\r\nlet foo = (elementOpen('span'), text('foo'), elementClose('span'));\r\n\r\nelementOpen('div');\r\nfoo;\r\nelementClose('div');\r\n```\r\n\r\nOr better put:\r\n\r\n```html\r\n<span>foo</span>\r\n<div></div>\r\n```\r\n\r\n### Solution\r\n\r\nTo get around this, one potential solution is to wrap jsx elements in shadow functions (arrow functions).\r\n\r\n```js\r\nlet foo = () => <span>foo</span>;\r\n\r\n<div>{foo()}</div>\r\n```\r\n\r\nThere's a couple of things to note here:\r\n- We have to handle other types of `{}` such as arrays or text nodes.\r\n- We don't want the second jsx block to be wrapped as it needs to be run at some point\r\n\r\nIn order to get around this we'll need to introduce a helper and a way of inferring you want the final block to not be wrapped.\r\n\r\n#### Helper\r\n\r\n```js\r\nfunction runtimeInsert(value) {\r\n  if (value instanceof Array) {\r\n    value.forEach(runtimeInsert);\r\n  } else if (value instanceof Function) {\r\n    value();\r\n  } else {\r\n    text('' + value);\r\n  }\r\n}\r\n```\r\n\r\n#### Return Statements\r\n\r\nSince the following is an example of how JSX is mostly used today, it makes sense to use ReturnStatement's as a way of deciding when not to wrap JSX in a shadow function.\r\n\r\n```js\r\nconst heading = <h1>Hello</h1>;\r\n\r\nclass Component {\r\n  render() {\r\n    let items = [1, 2, 3].map(n =>\r\n      <li>{n}</li>\r\n    );\r\n\r\n    return (\r\n      <div>\r\n        {heading}\r\n        <ul>\r\n          {items}\r\n        </ul>\r\n      </div\r\n    );\r\n  }\r\n}\r\n```\r\n\r\ntranslated to:\r\n\r\n```js\r\nfunction runtimeInsert(value) {\r\n  if (value instanceof Array) {\r\n    value.forEach(runtimeInsert);\r\n  } else if (value instanceof Function) {\r\n    value();\r\n  } else {\r\n    text('' + value);\r\n  }\r\n}\r\n\r\nconst heading = () => <h1>Hello</h1>;\r\n\r\nclass Component {\r\n  render() {\r\n    let items = [1, 2, 3].map(n => {\r\n      return () => {\r\n        elementOpen('li');\r\n        runtimeInsert(n);\r\n        elementClose('li');\r\n      };\r\n    });\r\n\r\n    return (\r\n      elementOpen('div'),\r\n      runtimeInsert(heading),\r\n      elementOpen('ul'),\r\n      runtimeInsert(items),\r\n      elementClose('ul'),\r\n      elementClose('div')\r\n    );\r\n  }\r\n}\r\n```\r\n\r\n### Potential issues\r\n\r\nIf a user does not follow the `return <div/>` pattern, their code won't run which may confuse people (although I feel this won't be a huge one).\r\n\r\n**Incorrect**\r\n```js\r\nfunction render() {\r\n  <div></div>\r\n}\r\npatch(document.body, render);\r\n```\r\n\r\n**Correct**\r\n```js\r\nfunction render() {\r\n  return <div></div>\r\n}\r\npatch(document.body, render);\r\n```\r\n\r\n**Correct**\r\n```js\r\npatch(document.body, <div></div>);\r\n```\r\n\r\nAlthough, hopefully most devs are used to this from React.\r\n\r\n### Other solutions\r\n\r\nJSX-IR gets around this by translating JSX into large nested objects wrapped in a runtime.\r\n\r\n```js\r\n<div className=\"box\">\r\n  <List>...</List>\r\n</div>\r\n```\r\n```js\r\n({\r\n  tag: \"div\",\r\n  props: {\r\n    className: \"box\"\r\n  },\r\n  children: [{\r\n    tag: \"List\",\r\n    props: null,\r\n    children: [...]\r\n  }]\r\n})\r\n```\r\n\r\nThis is not the right solution as it eliminates most of the benefits of using iDOM in terms of memory and performance."},"comment":{"url":"https://api.github.com/repos/babel-plugins/babel-plugin-incremental-dom/issues/comments/126861592","html_url":"https://github.com/babel-plugins/babel-plugin-incremental-dom/issues/8#issuecomment-126861592","issue_url":"https://api.github.com/repos/babel-plugins/babel-plugin-incremental-dom/issues/8","id":126861592,"user":{"login":"ivan","id":4458,"avatar_url":"https://avatars.githubusercontent.com/u/4458?v=3","gravatar_id":"","url":"https://api.github.com/users/ivan","html_url":"https://github.com/ivan","followers_url":"https://api.github.com/users/ivan/followers","following_url":"https://api.github.com/users/ivan/following{/other_user}","gists_url":"https://api.github.com/users/ivan/gists{/gist_id}","starred_url":"https://api.github.com/users/ivan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ivan/subscriptions","organizations_url":"https://api.github.com/users/ivan/orgs","repos_url":"https://api.github.com/users/ivan/repos","events_url":"https://api.github.com/users/ivan/events{/privacy}","received_events_url":"https://api.github.com/users/ivan/received_events","type":"User","site_admin":false},"created_at":"2015-08-01T04:36:45Z","updated_at":"2015-08-01T04:36:45Z","body":"(Deleting `return` behavior -> jsxroot attribute proposal until I'm really clear on everything.)"}}