{"action":"created","issue":{"url":"https://api.github.com/repos/meteor/react-packages/issues/169","labels_url":"https://api.github.com/repos/meteor/react-packages/issues/169/labels{/name}","comments_url":"https://api.github.com/repos/meteor/react-packages/issues/169/comments","events_url":"https://api.github.com/repos/meteor/react-packages/issues/169/events","html_url":"https://github.com/meteor/react-packages/issues/169","id":128672434,"number":169,"title":"What's next for React + Meteor 1.3","user":{"login":"yyx990803","id":499550,"avatar_url":"https://avatars.githubusercontent.com/u/499550?v=3","gravatar_id":"","url":"https://api.github.com/users/yyx990803","html_url":"https://github.com/yyx990803","followers_url":"https://api.github.com/users/yyx990803/followers","following_url":"https://api.github.com/users/yyx990803/following{/other_user}","gists_url":"https://api.github.com/users/yyx990803/gists{/gist_id}","starred_url":"https://api.github.com/users/yyx990803/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yyx990803/subscriptions","organizations_url":"https://api.github.com/users/yyx990803/orgs","repos_url":"https://api.github.com/users/yyx990803/repos","events_url":"https://api.github.com/users/yyx990803/events{/privacy}","received_events_url":"https://api.github.com/users/yyx990803/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/meteor/react-packages/labels/discussion","name":"discussion","color":"fbca04"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":26,"created_at":"2016-01-25T23:23:55Z","updated_at":"2016-01-30T15:39:26Z","closed_at":null,"body":"With the ES2015 modules being enabled in Meteor 1.3, we are planning to recommend a new, better workflow for working with React in Meteor. Here's the outline:\r\n\r\n## Direct npm installs\r\n\r\nUsers now are encouraged to install React directly from npm using `npm install react react-dom` (and any additional addons needed) instead of `meteor add react`.\r\n  \r\n#### Benefits of this approach:\r\n  \r\n  - The current `react-runtime` packages require manual updates to stay up-to-date with React’s frequent release schedule. When installing directly from NPM, users can easily select the specific version of React and the specific list of React addons they want to use.\r\n    \r\n  - It is now much easier to work with 3rd party npm packages that expect React to exist as a peer dependency and directly `require(‘react’)`  in their code. Previously we had to use a Browserify-based hack to replace these.\r\n\r\n#### Potential issues:\r\n  \r\n  - Backwards compatibility with old packages or apps that depend on `react-runtime`. Luckily as of release [`1.3-modules-beta.5`](https://github.com/meteor/meteor/issues/5788#issuecomment-174621057), packages can now directly import top-level `node_modules` in an app. The new `react-runtime` package would simply be setting the global `React` by using the npm installed version. If React is not installed from npm, there would be a warning prompting you to do so.\r\n\r\n## Meteor Data Integration\r\n\r\nThe community has been looking for a new pattern to use instead of the mixin approach used by `react-meteor-data`, especially now that ES2015 is the default language, we don't want Meteor's default data integration to block users from using the class-based React component syntax.\r\n\r\nThere is a lot of community innovation going on in this space, e.g. Arunoda’s work on Mantra. [MDG is also working on major improvements to Meteor's data layer](http://info.meteor.com/blog/reactive-graphql). At this very moment, the absolute best practice is yet to be defined. So for now what we are going to provide is a minimal addition to the current `react-meteor-data` package, essentially a higher-order-component based on the current `ReactMeteorData` mixin:\r\n\r\n``` js\r\nimport React from 'react';\r\n\r\nReactMeteorDataContainer = function (Component, getMeteorData) {\r\n  return React.createClass({\r\n    mixins: [ReactMeteorData],\r\n    getMeteorData() {\r\n      return getMeteorData(this.props);\r\n    },\r\n    render() {\r\n      return <Component {...this.data} />\r\n    }\r\n  });\r\n};\r\n```\r\n\r\nAnd with modules, an example component using this function:\r\n\r\n``` js\r\nimport React from 'react';\r\nimport { Meteor } from 'meteor/meteor';\r\nimport { Todos } from '../lib/collections';\r\nimport { ReactMeteorDataContainer } from 'meteor/react-meteor-data';\r\n\r\n// The app component is \"pure\" and only depend on props\r\nexport class App extends React.Component {\r\n  render() {\r\n    return (\r\n      <div>\r\n        <h1>App!</h1>\r\n        <p>{ this.props.loading ? 'loading...' : '' }</p>\r\n        <ul>\r\n          {this.props.todos.map((todo, i) => {\r\n            return <li key={i}>{ todo.text }</li>\r\n          })}\r\n        </ul>\r\n      </div>\r\n    )\r\n  }\r\n};\r\n\r\n// The \"container\" simply wraps the app component and feeds data to it as props.\r\nexport const AppContainer = ReactMeteorDataContainer(App, () => {\r\n  const handle = Meteor.subscribe('todos');\r\n  return {\r\n    loading: !handle.ready(),\r\n    todos: Todos.find().fetch()\r\n  };\r\n});\r\n```\r\n\r\nThis pattern goes along with the ideas discussed in [Presentational and Container Components](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.mjvm5qt97) and [Let's Compose some React Containers](https://voice.kadira.io/let-s-compose-some-react-containers-3b91b6d9b7c8#.u0q8oqrd0). The main benefit is that the presentational/dumb/pure components can be individually imported in tests and easily tested because they only depend on props. It also makes refactoring easier because the rendering logic and the data management logic is decoupled.\r\n\r\nIn addition, very often the pure version can be further simplified to a stateless functional component:\r\n\r\n``` js\r\nexport const App = ({ loading, todos }) => (\r\n  <div>\r\n    <h1>App!</h1>\r\n    <p>{ loading ? 'loading...' : '' }</p>\r\n    <ul>\r\n      {todos.map((todo, i) => {\r\n        return <li key={i}>{ todo.text }</li>\r\n      })}\r\n    </ul>\r\n  </div>\r\n);\r\n```\r\n\r\nThe container syntax is not set in stone, so any suggestions/concerns are welcome. We are working on an example app (equivalent of [meteor/todos](https://github.com/meteor/todos) but for React) using Meteor 1.3 and the npm-based workflow, and will be adding the updated React integration docs as a new chapter to the Meteor Guide."},"comment":{"url":"https://api.github.com/repos/meteor/react-packages/issues/comments/177212326","html_url":"https://github.com/meteor/react-packages/issues/169#issuecomment-177212326","issue_url":"https://api.github.com/repos/meteor/react-packages/issues/169","id":177212326,"user":{"login":"markoshust","id":437029,"avatar_url":"https://avatars.githubusercontent.com/u/437029?v=3","gravatar_id":"","url":"https://api.github.com/users/markoshust","html_url":"https://github.com/markoshust","followers_url":"https://api.github.com/users/markoshust/followers","following_url":"https://api.github.com/users/markoshust/following{/other_user}","gists_url":"https://api.github.com/users/markoshust/gists{/gist_id}","starred_url":"https://api.github.com/users/markoshust/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/markoshust/subscriptions","organizations_url":"https://api.github.com/users/markoshust/orgs","repos_url":"https://api.github.com/users/markoshust/repos","events_url":"https://api.github.com/users/markoshust/events{/privacy}","received_events_url":"https://api.github.com/users/markoshust/received_events","type":"User","site_admin":false},"created_at":"2016-01-30T15:39:26Z","updated_at":"2016-01-30T15:39:26Z","body":"@arunoda thank you for the article. I sort of understood it before, but not really. This clarified a lot.\r\n\r\nFYI, I would update the example in your README. I think that it is throwing a lot of people off because it appears overly verbose. I'd even remove the `const` assignment there to simplify it further.\r\n\r\nIn the README:\r\n```\r\nconst Time = ({time}) => (<div>Time is: {time}</div>);\r\nconst composerFunction = (props, onData) => {\r\n  const handler = Meteor.subscribe('serverTime');\r\n  if(handler.ready()) {\r\n    const {time} = ServerTimeCollection.findOne();\r\n    onData(null, {time});\r\n  } else {\r\n    onData(null, null);\r\n  }\r\n};\r\n\r\n// Note the use of composeWithTracker\r\nconst Clock = composeWithTracker(composerFunction)(Time);\r\n```\r\n\r\nThis example is a lot easier to understand for someone coming from `ReactMeteorData` mixin usage:\r\n\r\n```\r\nimport {composeWithTracker} from 'react-komposer';\r\nimport PostList from '../components/post_list.jsx';\r\n\r\nfunction composer(props, onData) {\r\n  if (Meteor.subscribe('posts').ready()) {\r\n    const posts = Posts.find({}, {sort: {_id: 1}}).fetch();\r\n    onData(null, {posts});\r\n  };\r\n};\r\n\r\nexport default composeWithTracker(composer)(PostList);\r\n```\r\n\r\nI think moving the main component to a separate file is actually easier to understand, because it represents a real-life example and is more compartmentalized. I think using standard collection usage (collection.find().fetch()) also will help others 'get it'. Now, with this example, it's easy to understand and implement, whereas before I wasn't quite sure what is going on. "}}