stacks.js icon indicating copy to clipboard operation
stacks.js copied to clipboard

Use functional approach without mutations?

Open aryzing opened this issue 1 year ago • 0 comments

Problem

In reactive FE libraries like React, mutating deeply nested data can make it difficult to sync the UI with the data. For example, setting a new fee mutates the auth property,

https://github.com/hirosystems/stacks.js/blob/2cf886b6419232dbb54caccf5216b4f42605f3ad/packages/transactions/src/transaction.ts#L236-L238

Even explicitly setting the data may not be sufficient,

function handleFeeChange(newFee) {
  transaction.setFee(newFee); // mutates inner prop
  setTransaction(transaction); // outer transaction object still has same ref. equality
}

Even after the above code, transaction has the same referential equality, which prevents memos from running or components from rendering.

Solution

Having a functional approach which avoids mutations would help with reactive UI frameworks.

The API could look something like,

const nextTransaction = setFee(transaction, newFee);

function setFee(transaction, newFee) {
  return {
    ...transaction,
    auth: createAuth({...transaction.auth, fee: newFee}),
  };
}

Workaround

Currently, the only way to preserve reactivity seems to be with something like

const [auth, setAuth] = useState(transaction.auth); // fee is stored in this object

function handleNewFee(newFee) {
  transaction.setFee(newFee);
  setAuth(transaction.auth);
}

return <div>{auth.fee}</div>

which is suboptimal since transaction is no longer the source of truth for fee, and it's all to easy to accidentally reach out for transaction.auth.fee in a reactive context and break the UI.

aryzing avatar Nov 25 '24 11:11 aryzing