dai-shi / react-tracked

State usage tracking with Proxies. Optimize re-renders for useState/useReducer, React Redux, Zustand and others.
https://react-tracked.js.org
MIT License
2.73k stars 72 forks source link

How to work with arrays? #20

Closed Lani closed 5 years ago

Lani commented 5 years ago

Hi,

I just found react-tracked and was really intrigued by the simple api. But I'm having trouble getting it to work to just re-render the state that has changed. I tried to follow the quick-start, but I'm using an array instead of an object as a state.

When I update an item in the array in an immutable way (recreating the whole array) then all items still rerender. It also slowed down the whole application and made firefox consume a lot of cpu.

I guess that my approach is completely wrong and could even be related to my current understanding of javascript/react.

I created a codesanbox that illustrates the problem. It shows the date and time in seconds every time the todo-component is rerendered.

If you have the time it would be interesting to get your feedback on what I'm supposedly are doing wrong here :)

Thanks, Niklas

dai-shi commented 5 years ago

Hi! Thanks for your interest!

Yeah, I know what's happening. Here's the modified codesandbox. https://codesandbox.io/s/typescript-react-react-tracked-todo-qpy1b You need to use function update for setTodos. Otherwise, onChange is renewed every render.

It also slowed down the whole application and made firefox consume a lot of cpu.

I'm not sure if this is related to this, but curious if it's because of the library.

Lani commented 5 years ago

Yes, of course, thank you for looking at it and pointing that out, it takes some time to get used to the hooks way of things. After that modification, it works with the memo version. But I thought that if I used this library it would keep track of the usings and I wouldn't have to use memo?

I removed the memo around the todo component and then it updates all todos if I change one todo: https://codesandbox.io/s/typescript-react-react-tracked-todo-n4fhe

But I don't think that the cpu usage was related to this library, it was in the codesanbox demo that I got it. But I got the same with a pure context version as well, removing the console.log dropped it down to half. It was when I typed a lot quickly into a todo that it happened. Hopefully related to codesandbox and/or development mode of react. The pure context version of the example is here: https://codesandbox.io/s/typescript-react-context-todo-zcl82

dai-shi commented 5 years ago

But I thought that if I used this library it would keep track of the usings and I wouldn't have to use memo?

You still need memo in this pattern, because the parent component renders and that triggers children to render too. That's how React works. If your app uses only immutable objects, you can simply add React.memo to all components.

The alternative is something like this: https://codesandbox.io/s/typescript-react-react-tracked-todo-y46p0 Only pass id or index from the parent to children, and the children read items from the store based on the id or index. I sometimes see this pattern in Redux, but I personally prefer the React.memo pattern.

Lani commented 5 years ago

I see. Thank you for taking time out of your day to answer my questions. I hope that you have a continued nice weekend :)

dai-shi commented 5 years ago

https://codesandbox.io/s/typescript-react-react-tracked-todo-y46p0 I sometimes see this pattern in Redux, but I personally prefer the React.memo pattern.

Yet another alternative would be to have id list only.

state = {
  itemIds: ['id1', 'id2', 'id3'],
  itemMap: {
    id1: { text: 'My first todo', done: false },
    id2: { text: 'My sedond todo', done: true },
    id3: { text: 'My third todo', done: false },
  },
};

This might be more straightforward.

Thorvarium commented 7 months ago

Hey @dai-shi , sorry for resurrecting this.

Do you have an example of it being used as part of an object in the context? Example:

person = { firstName: "blabla", lastName: "blabla", todo: [] }

I am trying to use with useReducer inside the createContainer (typescript example), but I am having issues of the "TodoList" component rendering all "todo" 's, or worse, not rendering at all when I change something depending on how I use the reducer

dai-shi commented 7 months ago

Can you create a minimal reproduction? Are you using useMemo or React.memo?

Thorvarium commented 7 months ago

Can you create a minimal reproduction? Are you using useMemo or React.memo?

I've figured out after a lot of messing around, thanks. I had one of the parameters not memoized causing the re-render of all childs image