essessa
essessa

Reputation: 21

Update a props on a component rendered with the help of useTracker

I want to update the props of several component rendered by a tracker (by using useTracker), to update the front without refreshing the page.

Here's a simple example of my problem :

My collection is ValuesCollection with 1 attribute by default (myValue) : { "myValue" : "defaultValue", "key" : "uniqKey"}

In the backend, a batch change this value to another value (take 10 sec per batch)

import { useTracker } from "meteor/react-meteor-data";
import { ValuesCollection } from "api/MongoAPI";

export default function MyPage() {
  const { values } = useTracker(() => {
    Meteor.subscribe("values", {});
    const values = ValuesCollection.find({}).fetch();
    return { values };
  });

  return (
    <Stack spacing={2}>
      {values.map((elem) => (
        <ValueComponent key={elem.key} myProps={elem.myValue}/>
      ))}
    </Stack>
  )
}

When i load the page with 5 object in ValuesCollection, i have

<Stack spacing={2}>
  <ValueComponent key=1 myProps="defaultValue"/>
  <ValueComponent key=2 myProps="defaultValue"/>
  <ValueComponent key=3 myProps="defaultValue"/>
  <ValueComponent key=4 myProps="defaultValue"/>
  <ValueComponent key=5 myProps="defaultValue"/>
</Stack>

After 10 seconds, my first object is updated in database, with myValue="first". My tracker values is updated, but my ValueComponent doesn't re render. So, nothing happen on my front page.

<Stack spacing={2}>
  {/* Here, i want
  <ValueComponent key=1 myProps="first"/>
  */}
  <ValueComponent key=1 myProps="defaultValue"/>
  <ValueComponent key=2 myProps="defaultValue"/>
  <ValueComponent key=3 myProps="defaultValue"/>
  <ValueComponent key=4 myProps="defaultValue"/>
  <ValueComponent key=5 myProps="defaultValue"/>
</Stack>

How can I do to update my component as the collection updates to display the results in live ?

Upvotes: 0

Views: 135

Answers (2)

Lalo Mores
Lalo Mores

Reputation: 91

The usage of useTracker seems fine. And if you have tested that values actually changes, then it also works fine (as Hugo Mallet suggests in the comments). I think two suspects are in place:

  1. You are not using the MyProp prop inside your ValueComponent
  2. As your collection doesn't seem to have a key prop, it is possible you're assigning "undefined" as the key for all the items. Weird stuff happens when you mess with the keys. Do you get a warning in the console saying you have duplicate keys in your example? In such case you could could change the key={elem.key} with key={elem._id} to fix it up.

A debugging suggestion that would address both: log both key and MyProp inside your ValueComponent and see what you get.

Also, sharing the code of your ValueComponent would help.

Upvotes: 1

Paul Paulincai
Paul Paulincai

Reputation: 644

In order to refresh a React component you need to update the local state or the props. None of this is happening in your component. This is why in React you have mainly two options (and a third which I use in all my projects)

  1. React context - pass props down to components
  2. React containers - wrap a component into a data container
  3. Redux - global store
  4. Other global store solutions.

For a simple case like yours, separating data from the view would be the easiest thing to do and solution 2 is the easiest to implement. If you need to do this in a large project, 1 or 3 would be your best options.

Ok there could be another way. In your tracker function include a state update. You don't need to use it further, just to update it.

e.g.


const [lastUpdate, setLastUpdate] = React.useState(null)

//....
useTracker(() => {
    Meteor.subscribe("values", {});
    const values = ValuesCollection.find({}).fetch();
    return { values };
    setLastUpdate(Date.new())
  })


Upvotes: 1

Related Questions