skip to Main Content

I have a Card component, which gets passed a CryptoAsset instance. The class stores relevant information such as Assets ticker, amount, value, etc.

I tried to use an useEffect hook in the beginning to track if the class information gets changed, and for some reason it is not firing unless the component has re-rendered after it’s values updated.

(I have updatePrice method, which changes the current CryptoAssets price)

So I simply have created an useState which is used only for the re-rendering the component.

const Card = ({ asset }: CardProps) => {
  // Using an array destructuring to get the setRefresh function.
  const [, setRefresh] = useState(0);

  useEffect(() => {
    asset.updatePrice();
    refresh();
  },[asset])

  const refresh = () => {
    setRefresh((prevValue) => prevValue + 1);
  };

I have removed the first variable from the array so it doesn’t give me an unused var warning.

But this leaves me with a question, if the CryptoAssets values change in future, would it be possible to track it with useEffect? Or do I always have to invoke the refresh function in order to keep the component with correct information? And is this a correct way of doing this?

2

Answers


  1. React components rerender for a few reasons:

    • Local state was updated
    • Passed prop values changed
    • The parent component rerendered (renders entire sub-ReactTree)

    Ideally in React you would update an entire reference to an object that is stored in state and this will automatically trigger a component rerender. This is the typical shallow copying of arrays and objects into new array and object references, a pattern commonly referred to as the Immutable Update Pattern.

    Examples:

    setArrayData(arrayData => arrayData.map( // <-- new array reference
      el => el.id = id
        ? { ...el, updatedProperty } // <-- new object reference
        : el
    ));
    

    However

    Sometimes you might find yourself working with a non-React library that may utilize OOP patterns. It’s often the case here that you will instantiate an instance of this Class object and store it in a React ref. It’s impractical, and maybe even not possible, to just clone the object into a new instance each time you are updating its state. This is an edge case where it is acceptable to implement "forceUpdate" logic in a component.

    This would effectively be the React function component equivalent to the React Class component forceUpdate lifecycle method. From the documentation, I’ve emphasized the related use case.

    By default, when your component’s state or props change, your
    component will re-render. If your render() method depends on some
    other data, you can tell React that the component needs re-rendering
    by calling forceUpdate().

    It’s included as an escape hatch and should be used sparingly, basically as a "last resort" if there is not any immutable way to work with the external objects.

    Login or Signup to reply.
  2. You don’t need to output it to the refresh function but can edit the useState inside the useEffect:

    useEffect(() => {
        asset.updatePrice();
        setRefresh((prevValue) => prevValue + 1);
      },[asset])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search