-
Notifications
You must be signed in to change notification settings - Fork 123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reference changes without reason #258
Comments
First of all, the That being said, I'm not sure why but it seems that const ModelOneItem = React.memo(function ModelOneItem({ item }) {
console.log(item);
console.count("ModelOneItemRender");
return <pre>{JSON.stringify(item)}</pre>;
}); |
Thank you so much for your response. 1- parsing the needed fields by ourselves: const friends = ModelOne.withId(1).friends.toRefArray().map(f => { ...f, room: Room.withId(f.room) }) which is not efficient by any mean 😂 2- parsing fields separately in the selector: mapStateToProps = (state) => {
...
const data = session.X.all().toRefArray();
return {
data: data,
friends: data.map(d => session.Friends.withId(d.friend)),
}
} which preserves reference on the data, but seems too verbose to me. mapStateToProps = (state) => {
...
const dataQuerySet = session.X.all();
const friends = dataQuerySet.map(d => d.friend).toRefArray();
return {
data: dataQuerySet.toRefArray(),
friends: friends
}
} But with my knowledge of the codebase, both of these will almost have the same performance. So, do you think it's possible to keep the reference of the toModelArray result consistent? |
Yeah, I was also very surprised to see that it didn't work with The idea of combining the ref and model concepts looks less and less elegant to me, though. Tommi himself has also said the following in #58 (comment):
I have done it using a custom conversion function myself, as suggested in #180 (comment) as well. However that does create a new reference on each call which is arguably bad for performance. Values derived from other properties are highly useful in the view layer but we should probably not make sessions available there to interact with other models. In Redux data is not supposed to flow back from the view, other than by dispatching actions. Exposing sessions and models would enable that which would be encouraging a terrible practice [1]. Now, to allow for computed properties, I imagine we could define derived properties using the To avoid bugs, we might want to prevent setting those fields within The You are very welcome to contribute 🙂 🙂 Please let me know what you think of my suggestions, if you're still interested in this and if you need any further direction! [1] Values computed using relationships should stay in selectors. With #257 this will be way easier, so we can soon do the following: const xs = createSelector(orm.X);
// For a component listing all X models:
mapStateToProps = (state) => ({
xs: xs(state),
});
const XList = connect(mapStateToProps)(({ xs }) => xs.map(
x => <XFriends xId={x.id} />
));
// For a component listing a single X's friends:
// in XList: <XFriends xId={x.id} />
const xsFriends = createSelector(orm.X.friends);
const friendRoom = createSelector(orm.Friend.room);
const xsFriendRooms = createSelector(orm.X.friends.map(friendRoom));
mapStateToProps = (state, ownProps) => ({
friends: xsFriends(state, ownProps.xId),
friendRoom: xsFriendRoom(state, ownProps.xId),
});
const XFriends = connect(mapStateToProps)(({ friends, friendRoom }) => friends.map(
(friend, i) => <div>{friend.name} - {friendRoom[i].location}</div>
));
// Or a much cleaner component listing a single friend instead:
// in XFriends.render(): <Friend id={friend.id} />
const friends = createSelector(orm.X.friends);
mapStateToProps = (state, ownProps) => ({
friend: friends(state, ownProps.id),
room: friendRoom(state, ownProps.id),
});
const Friend = connect(mapStateToProps)(({ friend, room }) => (
<div>{friend.name} - {room.location}</div>
)); |
I can't wait for the new selectors API. It seems so nice and tidy. |
Ok. I found the problem with the pure component 😆 |
Didn't notice that either hah! Looks to only be the case for the many-to-many example but it's probably something similar in the other one. As for the new API, I just released a version 0.14.0-rc.0 for you to try out 🕺 |
Thank you so much for the release, I'm going to try it out. Also, about the computed properties, they are so needed. Currently, I'm going to write custom selectors for calculating properties based on other fields. But I'll work on your suggestion about adding support for computed properties to |
Meanwhile computed properties can be emulated this way: class Rectangle extends Model {
// ...
/**
* Act as if this method was a non-static function.
* It's only static because it needs to be accessible during Rectangle.create.
* `this` will be bound to the ref automatically.
*/
static area() {
return this.width * this.height;
}
static create(props) {
Model.create.call(this, {
...props,
area: this.area,
});
}
} In view (e.g. React): function RectangleComponent({ rectangle }) {
return (
<div>
<span>Area: {rectangle.area()}</span>
<span>({rectangle.width} x {rectangle.height})</span>
</div>
);
} |
Feels like a hack, using static as if non-static. I hope we can still consider merging refs and models with the help of Proxy (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) |
Yes it is a hack but it works for now. While using |
There's https://github.com/GoogleChrome/proxy-polyfill, probably imperfect depending on the use case. As for IE11 etc., a major version bump could help everyone to progress, but that's just my 2 cents as a non-maintainer. |
Hi.
Thank you for this impressive library.
I'm working on a project which is heavily relied on redux-orm for its state management and logic.
Recently, I had many issues about poor performance and lags, especially in long lists. So I started monitoring the bottlenecks and re-architecture the application. After cleaning up everything, I found this issue which makes many re-renders that are not needed.
So, here is what I have:
Consider having two models,
FakeModelOne
andFakeModelTwo
such thatFakeModelOne
has many-to-many(or many-to-one) relation withFakeModelTwo
. Now if we write a reducer which adds items to FakeModelOnes related field (UsingQuerySet.add(...)
), in the next iteration when we get every related instance ofFakeModelTwo.
The reference of old related instances has changed and thus, every component re-renders although they are using memo.Here are some code samples for clarification:
many-to-many
many-to-one
In both of these examples, we have a component which lists the related models, and when you press the button, a new model gets generated and added to the list, but if you take a look at the console, you will find out that every component in the list gets re-rendered, but there is no value change in their content.
The text was updated successfully, but these errors were encountered: