Baruc Almaguer
Baruc Almaguer

Reputation: 152

Why is the state not updating inside this react Hooks component?

I have a stateful component (using react hooks) and a stateless layout component. The state behaves unexpectedly, as in 2 functions defined inside the stateful component, one gets the current value of the state and the other one gets the default value of the state.

React version: 16.12.0

Snippet (full version on code sandbox https://codesandbox.io/s/sweet-smoke-tpjge):

import React, { useState } from "react";
import MapLayout from "./MapLayout";

function Map(props) {
  const [editMode, setEditMode] = useState(false);
  const items = [
    { id: 0, name: "item 0", pos: { x: 0, y: 0 } },
    { id: 1, name: "item 1", pos: { x: 0, y: 100 } }
  ];
  function onItemClick(item) {
    if (!editMode) return; // ! Expected to change with state
    console.log("On Edit mode"); // ! Never prints
  }
  function onMapClick(item) {
    if (!editMode) return; // ! this works fine
    console.log("On Edit mode"); // This prints OK
  }
  console.log("rerender, editMode value: ", editMode);
  return (
    <MapLayout
      editMode={editMode}
      toggleEditMode={() => {
        setEditMode(!editMode);
      }}
      items={items}
      onItemClick={onItemClick}
      onMapClick={onMapClick}
    />
  );
}

export default Map;

Steps To Reproduce

  1. Open Console log
  2. Click on any cyan item (should log item index and editMode value)
  3. Click on Map (white area, should log "MAP click" and editMode value)
  4. Click on toggle button (should change editMode value to true)
  5. Click on Map (should log same message plus "On edit mode")
  6. Click on any cyan item (should log same message plus "On edit mode", it doesn't)

The current behavior

EditMode value does not change on "onItemClick" function, but it does inside "onMapClick" function

The expected behavior

EditMode value should behave consistently across all function definitions inside its scope

Upvotes: 3

Views: 481

Answers (1)

TKoL
TKoL

Reputation: 13912

I figured it out

You goofed when you set this.onClick = props.onClick; in the constructor of Flowpoint.js

The problem with doing this is that this.onClick never updates when the props update, so it stays as the first function that you passed to it.

Instead of that line, do this in Flowpoint.js

onMouseUp(e) {
   // Trigger user-defined onClick?
   if (!this.didDrag) this.props.onClick(e);
   ...

Upvotes: 6

Related Questions