Bind the value into the function to avoid passing it to component explicitly

Viewed 28

I have the following code which passes values of an array of objects down to a component.

{
  recipes.value.map((recipe) => (
    <RecipeBrowserItem
      key={"browse-item-" + recipe.nodeId}
      isMember={recipe.isMember}
      slug={recipe.slug}
      members={recipe.teamRecipe.nodes[0].recipeMembers.totalCount}
      teamRecipeId={recipe.teamRecipe.nodes[0].id}
      teamMemberId={identity.teamMemberId}
      onClickJoin={handleClickJoinRecipe}
    />
  ));
}

On the actual component the onClickJoin takes both teamRecipeId and teamMemberId so I am passing them down just to use a callback, can at least teamRecipeId be binded so that I don't have to pass it down?

I am basically just doing

const handleJoinRecipe = useCallback(() => {
    onClickJoin(teamRecipeId, teamMemberId);
}, [teamRecipeId, teamMemberId]);
1 Answers

From what I understand of your question you want to avoid explicitly passing down the props to the mapped RecipeBrowserItem components.

First off, wrapping these props in a useCallback hook in the child isn't the point of memoizing a callback. Generally you want to memoize the callback in the parent component that is passing it down as a callback to children via props.

It sounds like you want to create a curried callback that closes over the identity.teamMemberId value and later takes a specifically mapped element object's recipe.teamRecipe.nodes[0].id property.

The pattern for this usually looks similar to the following:

const handleClickJoinRecipe = (teamRecipeId) => () => {
  const teamMemberId = identity.teamMemberId; // <-- close over in scope
  ... additional shared variables/logic ...

  ... use the passed teamRecipeId argument ...

  ...
};

Example usage:

{recipes.value.map((recipe) => (
  <RecipeBrowserItem
    key={"browse-item-" + recipe.nodeId}
    isMember={recipe.isMember}
    slug={recipe.slug}
    members={recipe.teamRecipe.nodes[0].recipeMembers.totalCount}
    onClickJoin={handleClickJoinRecipe(recipe.teamRecipe.nodes[0].id)}
  />
))}

If you need to memoize the handleClickJoinRecipe callback, do it in the parent component, using the appropriate dependencies for the values you want to close over in callback scope when they update.

Example:

const handleClickJoinRecipe = useCallback((teamRecipeId) => () => {
  const teamMemberId = identity.teamMemberId; // <-- close over in scope
  ... additional shared variables/logic ...

  ... use the passed teamRecipeId argument ...

  ...
}, [identity.teamMemberId]);

The child component now only needs to attach the passed onClickJoin to an element's onClick handler, it doesn't need to pass anything.

onClick={onClickJoin}
Related