Suppose you want to reuse a component A to create a new component B.

  • (1) The primitive method is to copy and paste the source code and modify some of it.
  • (2) A slightly more advanced method is
    • Component A is implemented as a class,
    • After bracketing out the part to be changed in the method,
    • Create class B by inheriting class A.
    • Override some methods
  • (3) Since this is a function component, a simple way to do this is to use the
    • Call function A from function B

image

However, the trouble is that func A has state X, and I want to access this state in func B. Note that “state X” here refers to the following two pairs.

  • Value x

  • Function setX to update the value x It can be obtained as a return value by calling useState.

  • (4) X is a local variable of func A, so it cannot be accessed from outside func A.

  • (5) So I thought of using func B to create X and pass it on (foreshadowing: so far so good)

    • X as an optional argument and use it when it is passed and func A makes it itself if not passed (foreshadowing: this is a mistake).
    • const [x, setX] = props.X ? props.X : useState(...);
    • This is NG.
      • React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render react-hooks/rules-of-hooks image
  • (6) Then, the code that handles state X should be bundled out of func A and designated func handleX,

    • I figured I could use that from A and B.
    • image
    • This is NG, because X in func A is not updated just because X in func B is updated.
    • They should not have had individual X’s.
  • (7) I created func C to combine components with state X into one.

By the way, I want to synchronize the state X of this component with the database on the server. Now what do we do?

  • Func It’s odd to put code for synchronization in C.
    • The actual name of func C was “DraggableSVGElement”.
    • It is clearly not sole responsibility to write database access code here.
  • Lifting State Up – React
  • Child components relinquish control of their own condition and delegate it to their parents
  • This is the first half of what I had in mind at the time of (5)
    • The mistake was in trying to express “a component that manages state X by itself” and “a component that depends on its parent to manage state X” in a single function in the latter half.
  • When you build a component from the bottom up, from the smallest part, you tend to want the component to be complete on its own.
    • This is similar to the idea of trying to create “parts” in a “stand-alone instantiable class.
    • That’s not the only way to implement it nowadays.
      • An entity that cannot be instantiated on its own like Mixin, but is mixed into the class
      • An entity that can only make an instance when it is with a Treate that provides “the method I require” as Treate does.
    • React components may not have the necessary “state” themselves to draw themselves or perform their functions
      • React is all about one-way data flow down the component hierarchy. It may not be immediately clear which component should own what state. This is often the most challenging part for newcomers to understand

Tomorrow we’ll reconstruct it based on this realization.


This page is auto-translated from /nishio/状態を持つ関数コンポーネントの再利用 using DeepL. If you looks something interesting but the auto-translated English is not good enough to understand it, feel free to let me know at @nishio_en. I’m very happy to spread my thought to non-Japanese readers.