Skip to content

Setter from useEntityProp should accept an updater function #70748

@cr0ybot

Description

@cr0ybot

What problem does this address?

When using the setter provided by useEntityProp() in an async function and you need to set a complex object with a partial update, it is likely that the original value within the closure is stale. For example, when using it to get and set meta, which is an object, we need to provide the entire meta object to the setter just to update a single meta value:

const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta', postId );

const handleAsyncTask = async () => {
  const result = await asyncTask();

  setMeta( { ...meta, taskKey: result } );
};

If the asyncTask() above takes long enough that other meta values have been updated in the interim, when setMeta() is finally called those other updates will be wiped out.

(Note that useCallback() does not help us here, and the setter already uses it under the hood)

This is a good overview of the stale closure issue in React: https://medium.com/@kristinethejohnson/i-need-closure-s-javascript-react-stale-closures-2881c5861303

What is your proposed solution?

The useEntityProp hook's return value includes a setter method as the second item of the array, which currently only accepts a static value to set in the current entity state. This setter should also accept an update function the same way that the setter returned by useState() does.

From https://react.dev/reference/react/useState#setstate :

If you pass a function as nextState, it will be treated as an updater function. It must be pure, should take the pending state as its only argument, and should return the next state.

Since the underlying editEntityRecord() mechanism fetches the current state to apply edits, it should be able to check for an updater function and provide the current state before applying the update.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions