I might be wrong but my impression is that state should be reserved for keeping track of the state of your UI while data is simply data. Not sure why you’d couple the two together? Then again, I’ve never done React outside of the basic tutorials.
I think that’s exactly what we are doing, by following the trends in future React development for the observe
API, and popular packages like Parse. Also, AFAIK people who use Flux definitely don’t put their server-side data on this.state
.
Okay. Got it now.
try to put this on the guide as well.
It’s worth mentioning it there.
@dgreensp we should write something up about this since people keep bringing it up.
Probably right next to this section: http://react-in-meteor.readthedocs.org/en/latest/meteor-data/#why-we-decided-to-ship-a-mixin
Call for community React related packages to put in guide
Hi everyone who has been posting in this thread! I want to compile a list of useful React+Meteor projects that have popped up since the initial release of these packages, and add them to the guide so that people don’t have to read all of the github issues to find this stuff.
I’m going to go through the conversations on GitHub looking for those projects, but if you have others that I should mention, let me know!
While you’re planning what to include in the docs, could you consider adding a section on refactor paths between Blaze and React? Ideally, something along the lines of the following:
Blaze in Separate Files <==> React in Separate Files <==> Single File React
[HTML, CSS JS] <==> [JSX, JSS, JS] <==> JS(JSX, JSS)
I opened up another thread this morning which details some use cases as to why these kinds of refactor paths are useful/important. Hopefully it will generate some community discussion. But I suspect this may need some MDG guidance as well.
Hi, I saw your thread over there. Let’s see what people say; if there is demand for more migration tools we can think about building them, but it looks like there are already some great community things about it, like the jsx-templating
package here: https://atmospherejs.com/timbrandin/jsx-templating
I suspect the need for refactoring between different view layers will be very application or situation specific, so it might make sense to have people build their own tools for that.
What’s the difference between this and reactjs:react
? I’ve just started using the latter with Webpack to integrate React, and nothing seems to be lacking yet.
How exactly do you mean about server-side data? Data from the server side (or something derived from it) pretty much has to go in the state of some component, even if that’s a controller-view that passes things from its state down via props.
I looked at the tutorials on this, I have to say I frankly don’t understand some things. I like how reactjs:react
puts getMeteorState()
in this.state
because then you can track that with the lifecycle methods like componentWillUpdate()
, shouldComponentUpdate()
, etc. Why this package puts things in this.data
instead (and calls forceUpdate()
I assume?), I don’t understand. I’m sorry, I’m going to keep promoting reactjs:react
unless I can see some kind of advantage to this package.
I’ve put the reactjs:react
mixin into a setState
infinite loop in certain edge cases. this.data
eliminates that.
Using this.state
may seem like a great idea but ideally you want your data coming from props. You should avoid this.state
whenever possible (many times it’s not).
The best pattern with Meteor so far is to use the container pattern. Your FeedListContainer
handles the subscription and mixin, sideloading the data from Meteor. It passes this.data
into it’s only component FeedList
as props. The container only has one job, gather data and push it down via props.
The FeedList
component now knows nothing about how it’s getting it’s data. It’s basically a pure function that has params (props). It’s now very re-useable and easy to test (it just takes in props). FeedList
can implement shouldComponentUpdate
to cancel rendering on children.
FeedListContainer = React.createClass({
mixins: [ReactMeteorData],
getMeteorData: function() {
var sub = Meteor.subscribe("feed");
return {
feedReady: sub.ready(),
postItems: Posts.find({}, {sort: {createdAt: -1}}).fetch(),
};
},
render() {
return (
<FeedList
isReady={this.data.feedReady},
postItems={this.data.postItems}
/>
);
}
});
and then the feed list…
FeedList = React.createClass({
propTypes: {
postItems: React.PropTypes.object,
isReady: React.PropTypes.bool,
},
render() {
if (!this.props.isReady) {
return <LoadingSpinner />
}
return (
<div className='FeedList-container'>
{
this.props.map(function(post) {
return <Post postData={post} />
})
}
</div>
);
}
});
[quote="jedwards, post:64, topic:6150"] How exactly do you mean about server-side data? [/quote]
I think @sashko was referring to Flux users who are loading serverside data are not using this.state
in their component. Instead the component merely triggers an action (say and action called PRESSED_LOAD_MORE
) and loads in data from the server. This data is stored in a Flux store (global state for a domain). The component just requests state from the Flux store on render and never touches setState
(you could use setState to load the Flux data but you don’t have to).
this.state
should really only (ideally) be used to keep track of transient state of a component… say which tab is open in a tab list, or what photo a gallery is indexed at… not the feed of post data. You can do this but it doesn’t scale well.
Hey, I think it’s totally legitimate to want that stuff in this.state
. Before you start using reactjs:react
again, let me suggest an alternative:
- Use the
react-runtime
package. This is the package that all Meteor packages and apps that use React should start depending on, so that you don’t end up shipping multiple versions of the React library. This package includes no mixins or anything else. - Use the
jsx
package. We have put a lot more effort into making it stable on all platforms, and it will be maintained as part of Meteor core moving forward. - Copy the mixin logic from
reactjs:react
into a new package - you could call itjedwards:get-meteor-state
. Now, you can use the pattern you like.
With this approach, you will get all of the benefits of using mostly core Meteor packages which are guaranteed to be maintained into the far future, while not having to use react-meteor-data
which you don’t like.
This is the reason we have published all of the parts of react
separately - exactly so that you can pick or choose the parts you like.
Were the setState
infinite loops triggered by the mixin itself or was your code doing Meteor work in shouldComponentUpdate
, componentWillUpdate
, or componentDidUpdate
that inadvertently triggered a call to getMeteorState
? I could imagine that if you need to respond to changes in transient state caused by the user, your code would accidentally get triggered by the getMeteorState
changes as well…
Not all websites are social media feed lists. If that’s all you’ve worked on you might get used to some patterns that work well, but they don’t necessarily work well for other kinds of websites (for instance, I’ve used setState()
with Immutables to improve performance in an interactive dashboard layout).
From the React website itself: setState(function|object nextState[, function callback])
“Merges nextState with the current state. This is the primary method you use to trigger UI updates from event handlers and server request callbacks.”
And I know about this container pattern (React actually calls it the controller-view pattern) and use it often. But still, my controller-views are often using setState
and passing down props from this.state
instead of using forceUpdate
or React.render
.
If Flux patterns shun this dictum from the horse’s mouth, how to do they trigger UI updates? forceUpdate
or React.render
?
My hesitation to use the jsx
package is that I don’t like dealing with the package global vars and script load order in idiomatic meteor…or does the jsx
package allow ES6 import
?
I was talking about it as an alternative to reactjs:react which also doesn’t have support for modules.
Probably the latter… to be honest I can’t remember the exact details.
[quote="jedwards, post:68, topic:6150"] Not all websites are social media feed lists. If that's all you've worked on you might get used to some patterns that work well, but they don't necessarily work well for other kinds of websites (for instance, I've used setState() with Immutables to improve performance in an interactive dashboard layout). [/quote]
I think it would still work well with that kind of app though? I’ve used it in a dashboard interface with lots of widgets. However I think that the extra layer is a bit cumbersome though.
Sure. After re-reading my post I didn’t mean to come across as anti-state. What I meant is the state is stored in the store, not the component. To be honest I haven’t looked too hard into the inner workings of the different flux implementations but some that i’ve seen use setState and others forceRender after re-fetching (Alt uses getInitialState and returns the store typically… not too familiar with others).
I’ve been wanting to tinker with using an immutable lib with Meteor and a Flux lib and somehow get data from the subscription in a store and then save into the immutable when the data changes… However I haven’t got any farther than that. With the latency compensation it might be fairly easy to do this in the store (as opposed to async) or even a utils folder.
Sorry, it’s just the typical anxiety I have these days of “what? the way I’m doing things is bad practice?”
Immutable is kind of cool, but it’s a bit cumbersome to use, so I only use it when the performance benefits outweigh the cumbersomeness, though I’ve also used it at times to avoid needing to return a copy of the data from the stores (when not using Meteor, that is)
@sashko @avital I’m not sure why I get this error:
Error: In template "board", call to `{{> React ... }}` missing `component` argument.
My code looks like this:
JavaScript:
MyComponent = React.createClass({
mixins: [ReactMeteorData],
render() {
return (
<div className={'famous-board-container '+this.props.board._id}></div>
)
},
onComponentDidMount() {
console.log('Mounted a React component.')
}
})
HTML:
{{> React component=MyComponent board=this }}
Ah, well, I found the workaround:
Template.blazeTemplateThatWillContainReact.onRendered(() => {
React.render(MyComponent, this.$('.targetElement')[0])
})
You need to pass in the component with a helper.