I don't understand this example from react-meteor-data
import { createContainer } from 'meteor/react-meteor-data';
export default FooContainer = createContainer(() => {
// Do all your reactive data access in this method.
// Note that this subscription will get cleaned up when your component is unmounted
var handle = Meteor.subscribe("todoList", this.props.id);
return {
currentUser: Meteor.user(),
listLoading: ! handle.ready(),
tasks: Tasks.find({listId: this.props.id}).fetch(),
};
}, Foo);
Why is it recommended to stop subscriptions when a Component is umounted but, in this case, no effort is made to stop anything? How does Meteor handle subscriptions, then? When are the collections cleaned? Are subscriptions stacking up every time the tracker callback is executed?
Or is Meteor smart enough to know when Meteor.subscribe is being called and does magic with the subscriptions?
The ReactMeteorData container runs createContainer's callback inside a reactive Tracker computation.
One of its features is stopping the subscription if the computation is invalidated or stopped.
If the function re-run produces an identical subscription, (same publication, same parameters) the library is smart enough and does not cancel and re-create the same subscription.
When the component is unmounted, the computation is stopped, the subscription is cancelled and not re-created (as the callback is not called again) and therefore automatically unsubscribed.
If you call Meteor.subscribe within a reactive computation, for example using Tracker.autorun, the subscription will automatically be cancelled when the computation is invalidated or stopped; it is not necessary to call stop on subscriptions made from inside autorun. However, if the next iteration of your run function subscribes to the same record set (same name and parameters), Meteor is smart enough to skip a wasteful unsubscribe/resubscribe.
(source: Meteor Docs)
Related
I have a browser application with the React-Redux architecture. Many events occur in the application (e.g. timeouts, web socket incoming messages, web workers messages, XHR responses, etc.). Each event emits a Redux action that changes the Redux store that causes a React render.
The problem is that the events occur so often that React doesn't have enough time to render the UI (for example, an event occurs every 5ms (or more often) and React takes 10ms to render the UI). It makes the whole page stop responding because the render process doesn't stop (it always has something to render) and the browser has no time to draw the DOM or handle a DOM event.
What are the approaches or ready solutions to solve this problem considering that I can reduce neither the events frequency nor the React render time?
When you update the state from a websocket message, record the time and only do another update if a certain amount of time has passed since then.
In this example the state is updated only if 1000ms have passed since the last update:
client.onUpdate(data => {
if (!this.lastUpdate ||
new Date().getTime() - this.lastUpdate.getTime() > 1000) {
this.setState({ data });
this.lastUpdate = new Date();
}
})
You can simply debounce your handler.
debounced function means it can be invoked only once in X period of time.
For the sake of the example I will not implement the details of debouncing a function, but rather use lodash.
// function that handles the server update.
const serverUpdateHandler = (dispatch) => {
dispatch({
type: SERVER_UPDATE
})
}
// create a new function that is debounced. aka - will invoke after 250 milliseconds after the lace invokation
const debouncedHandler = _.debounce(serverUpdateHandler,250);
// pass socket.io the debounced function
socket.on('server-update',debouncedHandler)
I'm performing server requests in my app within componentDidMount.So I'm calling setState within componentDidMount.Do I need to unmount this state within componentWillUnmount ?Is this is a solution for avoiding memory leaks in my app ?Please help me to find a solution for this.Thank you!
sample code
componentDidMount(){
fetch({ /* ... */ })
.then(res => res.json())
.then((responseData) => {
this.setState({
result: responseData.meta.data
})
})
}
componentWillUnmount(){
this.setState({
result:''
})
}
It's not needed to unmount the state. Setting result to empty string isn't any better than setting it to any other value.
The cause of memory leaks is that a reference to an object (component instance) is used somewhere, this prevents it from being garbage-collected as unused.
In this piece of code setState can be called after the component is unmounted because the request isn't cancelled. This will cause a warning:
Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
In case a request is long enough, this will cause a memory leak. In order to avoid it, a request or a promise that causes setState call needs to be cancelled. As for Fetch API request, can be done with AbortController.
React cleans the state of the component upon unmounting, so you don't have to reset the state on componentWillUnmount.
Something that can happen with performing request in components, is that your request can be completed after your component is unmounted again. At that point you're trying to perform setState on a component that isn't mounted. You'll receive an error in your console at that point.
Most HTTP libraries offer functionalities to cancel requests, this can be used to prevent that from happening. An example from the axios library here...
You wouldnt have to worry about cleaning up state while unmounting, as the reasons are already being highlighted by the people above.
But if you have left the listeners attached to your component "unremoved", then that might be a possible candidate for memory leak.
componentDidMount() can be used as a place to attach listeners and componentWillUnmount to remove those attached listeners.'
In Flux architecture, we use them to attach and remove listeners for events emitted from stores.
public componentDidMount() {
sampleStore.addListener('sampleEventFired', this.oncatch);
}
public componentWillUnmount() {
sampleStore.removeListener('sampleEventFired', this.oncatch);
}
In my Angular application, I have the subscription in every single component for watching if the user's Company change. On app init I download user's Company, so subscription fires once in every component I'm subscribing for changes in the state of the company (it's necessary because I am using this Company data in most of them). One of my components have a subscription to Company, and it downloads data once on init. When I change the view, a subscription is no more fired, so I need to download data. Code looks like
this.subscription = this
.companyService
.CompanyState
.subscribe((company: Company) => {
this.getSomeData()
})
this.getSomeData()
I've tried adding some flag like needDownload with default value true, and set it to false if subscription fires this.getSomeData(), but it's async and doesn't work very well.
If I remove the subscription from this component, I will stop watching changes on Company state. If I remove this.getSomeData() from the end of this code, I will not get data if the component is initiated without default call on subscription.
The problem is I am downloading data twice, and I feel like it's possible to do it once.
In your service, you can define companySubject as a ReplaySubject instead of a Subject. The buffer size can be set to 1, so that it "replays" only the last emitted value.
private companySubject = new ReplaySubject<Company>(1);
A new view will be notified as soon as it subscribes to the observable, if CompanyState has already emitted a value. As a consequence, you can remove the direct call to getSomeData() in your component initialization code.
See this answer for details about the various Subject classes.
in my code I created a hot observable with share() and if I don't complete the observable , or use setTimeout make it async, only the first subscription is executed, any additional subscription after it won't execute at all. Is this an expected behaviour?
const c=Rx.Observable.create((obs)=>{
obs.next(1)
// add this will work
// setTimeout(()=>obs.next(1),1000)
// add this will work too
// obs.complete()
}).share()
// excuted
c.subscribe(()=>console.log('first subscribe'))
// not excuted
c.subscribe(()=>console.log('second subscribe'))
and if I instead use publish connect approach it works as expected.
const c=Rx.Observable.create((obs)=>{
obs.next(1)
}).publish()
// excuted
c.subscribe(()=>console.log('first subscribe'))
// excuted
c.subscribe(()=>console.log('second subscribe'))
c.connect()
jsfiddle
Let's go through the example step by step.
Rx.Observable.create((obs)=>{
obs.next(1)
})
This creates an observable and the function you pass to create is executed when a subscription is requested.
.share()
This shares the upstream subscription. That means that the first subscriber makes share create a subscription to the source and all following subscribers share (sic!) this subscription. If all subscribers cancel their subscription the subscription to the source is cancelled as well. Note that a new subscription is also created when the stream has completed before.
c.subscribe(()=>console.log('first subscribe'))
The first subscriber subscribes, the share operator creates a shared subscription. Hence the subscription function is executed and a value is emitted.
c.subscribe(()=>console.log('second subscribe'))
The second subscriber subscribes and the share operator re-uses the already existing subscription to the source. Therefore the subscription function is not executed and no value is emitted.
If you add .unsubscribe() to the first subscribe then it would work as you expect it, because the shared subscription is cancelled and the second subscriber leads to another execution of the subscription function.
Where do sockets fit into the Flux unidirectional data flow? I have read 2 schools of thought for where remote data should enter the Flux unidirectional data flow. The way I have seen remote data for a Flux app fetched is when a server-side call is made, for example, in a promise that is then resolved or rejected. Three possible actions could fire during this process:
An initial action for optimistically updating the view (FooActions.BAR)
A success action for when an asynchronous promise is resolved (FooActions.BAR_SUCCESS)
An error action for when an asynchronous promise is rejected (FooActions.BAR_ERROR)
The stores will listen for the actions and update the necessary data. I have seen the server-side calls made from both action creators and from within the stores themselves. I use action creators for the process described above, but I'm not sure if data fetching via a web socket should be treated similarly. I was wondering where sockets fit into the diagram below.
There's really no difference in how you use Flux with WebSockets or plain old HTTP requests/polling. Your stores are responsible for emitting a change event when the application state changes, and it shouldn't be visible from the outside of the store if that change came from a UI interaction, from a WebSocket, or from making an HTTP request. That's really one of the main benefits of Flux in that no matter where the application state was changed, it goes through the same code paths.
Some Flux implementations tend to use actions/action creators for fetching data, but I don't really agree with that.
Actions are things that happen that modifies your application state. It's things like "the user changed some text and hit save" or "the user deleted an item". Think of actions like the transaction log of a database. If you lost your database, but you saved and serialized all actions that ever happened, you could just replay all those actions and end up with the same state/database that you lost.
So things like "give me item with id X" and "give me all the items" aren't actions, they're questions, questions about that application state. And in my view, it's the stores that should respond to those questions via methods that you expose on those stores.
It's tempting to use actions/action creators for fetching because fetching needs to be async. And by wrapping the async stuff in actions, your components and stores can be completely synchronous. But if you do that, you blur the definition of what an action is, and it also forces you to assume that you can fit your entire application state in memory (because you can only respond synchronously if you have the answer in memory).
So here's how I view Flux and the different concepts.
Stores
This is obviously where your application state lives. The store encapsulates and manages the state and is the only place where mutation of that state actually happens. It's also where events are emitted when that state changes.
The stores are also responsible for communicating with the backend. The store communicates with the backend when the state has changed and that needs to be synced with the server, and it also communicates with the server when it needs data that it doesn't have in memory. It has methods like get(id), search(parameters) etc. Those methods are for your questions, and they all return promises, even if the state can fit into memory. That's important because you might end up with use cases where the state no longer fits in memory, or where it's not possible to filter in memory or do advanced searching. By returning promises from your question methods, you can switch between returning from memory or asking the backend without having to change anything outside of the store.
Actions
My actions are very lightweight, and they don't know anything about persisting the mutation that they encapsulate. They simply carry the intention to mutate from the component to the store. For larger applications, they can contain some logic, but never things like server communication.
Components
These are your React components. They interact with stores by calling the question methods on the stores and rendering the return value of those methods. They also subscribe to the change event that the store exposes. I like using higher order components which are components that just wrap another component and passes props to it. An example would be:
var TodoItemsComponent = React.createClass({
getInitialState: function () {
return {
todoItems: null
}
},
componentDidMount: function () {
var self = this;
TodoStore.getAll().then(function (todoItems) {
self.setState({todoItems: todoItems});
});
TodoStore.onChange(function (todoItems) {
self.setState({todoItems: todoItems});
});
},
render: function () {
if (this.state.todoItems) {
return <TodoListComponent todoItems={this.state.todoItems} />;
} else {
return <Spinner />;
}
}
});
var TodoListComponent = React.createClass({
createNewTodo: function () {
TodoActions.createNew({
text: 'A new todo!'
});
},
render: function () {
return (
<ul>
{this.props.todoItems.map(function (todo) {
return <li>{todo.text}</li>;
})}
</ul>
<button onClick={this.createNewTodo}>Create new todo</button>
);
}
});
In this example the TodoItemsComponent is the higher order component and it wraps the nitty-gritty details of communicating with the store. It renders the TodoListComponent when it has fetched the todos, and renders a spinner before that. Since it passes the todo items as props to TodoListComponent that component only has to focus on rendering, and it will be re-rendered as soon as anything changes in the store. And the rendering component is kept completely synchronous. Another benefit is that TodoItemsComponent is only focused on fetching data and passing it on, making it very reusable for any rendering component that needs the todos.
higher order components
The term higher order components comes from the term higher order functions. Higher order functions are functions that return other functions. So a higher order component is a component that just wraps another component and returns its output.