Is there any way to trigger React.useEffect from different component?

Imagine two components like this in React:

import MyComponent2 from "./components/MyComponent2";
import React from "react";

export default function App() {
  const [myState, setMyState] = React.useState([]);

  React.useEffect(() => {
    console.log("useEffect triggered");
  }, [myState]);

  return <MyComponent2 myState={myState} setMyState={setMyState} />;
}
import React from "react";

export default function MyComponent2(props) {
  const [inputValue, setInputValue] = React.useState("");

  function handleChange(e) {
    setInputValue(e.target.value);
    let list = props.myState;
    list.push(`${e.target.value}`);
    props.setMyState(list);

    console.log(props.myState);
  }

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        name="text"
        onChange={handleChange}
      />
    </div>
  );
}

As you can see I am making changes with props.setMyState line in second component. State is changing but Somehow I could not trigger React.useEffect in first component even tough It is connected with [myState]. Why ?

In short form of my question : I can not get "useEffect triggered" on my console when i make changes in input

Upvotes: 0

Views: 368

Answers (1)

jsejcksn
jsejcksn

Reputation: 33787

Instead of providing myState and setMyState to MyComponent2, you should only provide setMyState and use the functional update argument in order to access the current state.

In your handleChange function you are currently mutating the React state (modifying it directly):

let list = props.myState; // This is an array that is state managed by React
list.push(`${e.target.value}`); // Here, you mutate it by appending a new element
props.setMyState(list);
// ^ You update the state with the same array here,
// and since they have the same object identity (they are the same array),
// no update occurs in the parent component

Instead, you should set the state to a new array (whose object identity differs from the current array):

props.setMyState(list => {
  const newList = [...list];
  newList.push(e.target.value);
  return newList;
});

// A concise way to write the above is like this:
// props.setMyState(list => [...list, e.target.value]);

Upvotes: 3

Related Questions