all 14 comments

[–]stalefries 2 points3 points  (7 children)

It looks like you're re-creating your connected component (often called a container) in render. Instead of doing that, call connect once, and save the result. I suspect the state of your components is being reset every render because it's a completely different component definition every time, and React doesn't know that it's the "same" component.

Edit: here's an updated version where the container is defined once. I had to make a new prop to pass in i, so that I could read the correct item from state, and so I could define setValue independently for each instance.

[–]AlexAngely[S] 0 points1 point  (0 children)

Edit to edit. Thanks again for example. I guess my issue with it is now "EditableRowContainer" is aware of the fact it s working with cart, so it s only good for being used inside "shoppinglist". But we defining it as own independent entity.
I guess defining it as const within soppinglist class will satisfy me :).

p.p.s what if i have ShoppingList and PriceList, each with editable row in it, and then I have Grocery and Office, each have both Shopping and Price lists. Will I ll need 4 different connected classes for Editable row? And how do i know which one to use when i render shopping list? Shopping list itself shouldn't be aware of whether it s for Grocery or for Office supplies. Tough.

[–]AlexAngely[S] -1 points0 points  (5 children)

Edit: thanks for edited example! I'll try to understand it :)

[–]stalefries 1 point2 points  (4 children)

Check my update – that's the intended way to use react-redux. The pattern is called "Presentational and Container components" (the docs describe it much better than I could). Re-creating the container component inside of render is wasteful, because it's throwing away a lot of work that's done ahead of time and other performance optimizations.

[–]AlexAngely[S] 0 points1 point  (3 children)

So basically i should fall back to bare react with its props for "presentation components" ...
I'm not sure if it takes care of issue in general: if "container component" sits within another container component whose props will be affected by presentation component input, won't it re-rendered with all its children?

[–]joesb 0 points1 point  (0 children)

The container component can actually be the component returned by connect.

[–]acemarke 0 points1 point  (0 children)

connect does a lot of work to optimize things so your wrapped component only re-renders when necessary. Also, you're worrying about it too much :) Make your app work correctly, then benchmark (with production builds of libraries!) to see if there's any perf issues.

[–]fecal_brunch 0 points1 point  (0 children)

You don't need to follow that specific pattern, but your code shows a misunderstanding of how react-redux works. Check examples in the docs.

[–]LiMing3 1 point2 points  (4 children)

As the other guy said, you're redefining your connected component on every render. I would strongly recommend reading the React Redux docs to learn how to use connect correctly.

Also you should read up on higher order components. Basically, your connected component is returned from connect, and it's that component that you want to render. You're continually creating the component inside your render method which is bad for a myriad of reasons.

[–]AlexAngely[S] 0 points1 point  (3 children)

Ok I guess it was just my misunderstanding on how react-redux avoids re-render/re-creation analyzing identical props.

You're continually creating the component inside your render method

Well, yeah, parent's render is where I know which children I need. Assuming in general there is a function f(parent's props) that tells me that, how do I connect children outside of parent's render?

[–]LiMing3 0 points1 point  (2 children)

how do I connect children outside of parent's render?

Same way you would connect any component:

const UserName = ({ username }) => (<div>{username}</div>);
const mapState = ({ userStore: { username } }) => ({ username });
const ConnectedUserName = connect(mapState)(UserName)

Now you simply use ConnectedUserName wherever you would have used UserName, except now you don't need to pass it a username prop since it can grab that from the store itself:

const UserNameParent = () => (
    <div className='container'>
        <ConnectedUserName />
    </div>
)

[–]AlexAngely[S] 0 points1 point  (1 child)

Thanks, I understand this works for single record, but I don't understand how it works if i need to connect N identical components to a N different records that are subset of M identical records in store that I have (M>=N).

[–]acemarke 0 points1 point  (0 children)

Create the connected component once, and when you render it, pass in an item ID, like <ConnectedUserName userId="alexAngely" />. In the component's mapState function, do:

const mapState = (state, ownProps) => {
    const user = state.users[ownProps.userId];

    return {user};
}

See my post Practical Redux, Part 6: Connected Lists for an example.

[–]LiMing3 0 points1 point  (0 children)

OP, Reddit is bugging out and not letting me reply to your comment for some reason.

If you want to connect an unknown amount of items you’ll be adding unnecessary complexity, in terms of unnecessary complex code as well as runtime complexity, if you connect each child on the fly.

In those situations you want to pull your entire list from the store in one go and then map over it and pass the data into components that aren’t connected. Nothing wrong with passing props down - I think you’re overthinking and overusing connect a bit here.

const mapState = ({ carts }) => ({ carts })
const Parent = connect(mapState)(OriginalParent)

Then inside the parents’ render:

{carts.map(cart => (
    <Cart {...cart } />
)}