Giter Club home page Giter Club logo

Comments (17)

speedskater avatar speedskater commented on June 28, 2024

@EatYourSpinach I think you have two possible solutions:

  1. use immutable.js for your structure. This sould ensure that unless you update your specific product the corresponding reference stays the same.
  2. You could use a custom equals functions which does a deep equality checking on products. This has the disadvantage that the deep equality check can become quite costly.

from reselect.

ellbee avatar ellbee commented on June 28, 2024

I'm not sure Immutable.js or a deep equality check will help here as every time a product is updated categoriesSelector will still create a new newCats and then a new newProds array for each category whether a product in that category has changed or not, potentially triggering an entire re-render.

I wonder how much of a problem this actually is however. The pureRender mixin uses shallowEqual for its equality check:

function shallowEqual(objA, objB) {
  if (objA === objB) {
    return true;
  }

  if (typeof objA !== 'object' || objA === null ||
      typeof objB !== 'object' || objB === null) {
    return false;
  }

  var keysA = Object.keys(objA);
  var keysB = Object.keys(objB);

  if (keysA.length !== keysB.length) {
    return false;
  }

  // Test for A's keys different from B.
  var bHasOwnProperty = Object.prototype.hasOwnProperty.bind(objB);
  for (var i = 0; i < keysA.length; i++) {
    if (!bHasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {
      return false;
    }
  }

  return true;
}

So pureRender is able to detect whether the contents of a category.products array has changed when it is passed as a prop.

from reselect.

cag-oss avatar cag-oss commented on June 28, 2024

immutability would help because it doesn't depend on reference equality at all, it can detect that category.products has had a product altered by comparing directly against the old version of category.products. PureRender, however, will always see category.products as !== oldCategory.products because the reference changes every time.

from reselect.

ellbee avatar ellbee commented on June 28, 2024

@EatYourSpinach Just to clarify, I meant that pureRender should work for a component that receives category.products directly as a prop. Components higher in the tree would still re-render each time (which may or may not be a problem).

from reselect.

cag-oss avatar cag-oss commented on June 28, 2024

It's precisely in this case that pureRender won't work, because a new array is getting created (newProds) each time we recompute the selector. But you're right, in many cases that may not be a problem at all. I'm still thinking through how to best use the selector concept...part of me wants to throw it at everything, because it acts like a materialized view and nicely takes care of 'joins' of separate but related data. But then I think it might be overkill to over-use it, as there's many cases where you could be needlessly recomputing things. I think you can achieve similar things with vanilla redux in some cases, but it's not as pretty. You end up having to repeat yourself/micromanage related but separate data, especially if both pieces of data arrive asynchronously at different times.

from reselect.

speedskater avatar speedskater commented on June 28, 2024

@EatYourSpinach @ellbee I think once again it depends :).

As a general rule of thumb i would recommend:

  1. Ensure that a component's selectors are stable for the entire component's lifecycle (creating selectors on the fly will result in rerenders because there is no memoized value)
  2. Ensure that the input selectors are chosen as specific as possible to prevent unnecessary rerenders.

from reselect.

ellbee avatar ellbee commented on June 28, 2024

@EatYourSpinach Maybe I'm missing something. My understanding is that shallowEquals doesn't check the reference of an object, it checks the contents one level deep, which in this case are the objects from the store, which should have the same references if they haven't changed. So, the fact that a new array is getting created doesn't matter when the contents are the same.

from reselect.

speedskater avatar speedskater commented on June 28, 2024

@ellbee I think it doesn't matter as long as the input selector doesn't change

from reselect.

cag-oss avatar cag-oss commented on June 28, 2024

@ellbee You're right! I had stupidly assumed that shallowEqual would bail false on different arrays, but it doesn't, it returns true: shallowEqual([1,2,3], [1,2,3]) === true. Thanks!

from reselect.

cag-oss avatar cag-oss commented on June 28, 2024

@speedskater Those are good points thanks. I guess it wouldn't make sense to have selectors for individual items in an array? I'm not 100% sure of what I'm getting at here, but using my initial example, what if you had a selector for each category, which would populate its own products array? Now we'd have to manage category selector lifecycles maybe, also not sure how I'd compose these things.

from reselect.

ellbee avatar ellbee commented on June 28, 2024

@speedskater I like those rules of thumb. I think we should mention them in the docs. I'll add to #22

from reselect.

speedskater avatar speedskater commented on June 28, 2024

@elbee thank for adding them to #22
@EatYourSpinach having individual selectors for an item in an array can actually make sense. We are currently experimenting with a hiearchical list where we use selectors to estimate the size of each item in the topmost array. In this special case the selectors are bound to the lifecycle of the topmost corresponding component (actually stored in its state). When this topmost component goes out of scope the selectors are outomatically garbage collected.
In your case maybe you could create the product selectors by a selector defined on your categories in the reducer itself. This selector on your category can for example be memoized by lodash.memoize. With this strategy the lifecycle of your product selectors should be automatically bound to the lifecycle of your categories.

I hope this was not to weird. Might this be a solution for you?

from reselect.

cag-oss avatar cag-oss commented on June 28, 2024

Not weird at all thank you for explaining that. Let me digest that a second.

from reselect.

oyeanuj avatar oyeanuj commented on June 28, 2024

@EatYourSpinach Wondering where you ended up with your initial problem here? I have the same problem but with many nested levels (one element referring to another to another) and I am wondering what is the best way to go about it (wanting to prevent re-render anytime the state.products in your example changes..

from reselect.

cag-oss avatar cag-oss commented on June 28, 2024

I kind of punted on the notion of computed data for now. It's too complicated and I want to keep things fairly simple. I just use helper functions to select/combine the data I want at any given level of the component hierarchy. Its a little ugly because I'm passing parameters down the tree multiple levels, but I prefer it for now because its very explicit and doesn't require much thought.

from reselect.

oyeanuj avatar oyeanuj commented on June 28, 2024

So, essentially, compute or select data for lower-level components - distribute the load instead of doing it at a higher level component?

That does make me a little uncomfortable, especially as lower-level components aren't 'dumb' anymore.

@ellbee Is there a recommended approach to such problems? I imagine it wouldn't be an uncommon problem for those who use redux, normalizr and want to take advantage of reselect?

from reselect.

ellbee avatar ellbee commented on June 28, 2024

It is somewhat of a compromise, but I would say that it's absolutely fine to have connects lower down the tree if that is what the structure of your app dictates.

from reselect.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.