skip to Main Content

I’m new to React and am trying to make a master detail view. I’ve made a sandbox example of what I’m trying to do. https://codesandbox.io/s/black-darkness-hp5eek
The issue is, the child component is not updating it’s value. I’m sure I’m doing something simple.
I can do a

console.log(props.dataItem);

in the details component and the object is being passed in correctly. But the state in the details component is not displaying

3

Answers


  1. Look at what your Details component does:

    function Details(props) {
    
      console.log(props.dataItem);
    
      const defaultItem = {
        company: "",
        ticker: "",
        stockPrice: ""
      };
    
      const [dataItem, setDataItem] = useState(defaultItem);
    
      useEffect(() => {
        setDataItem(props.dataItem);
      }, []);
    
      if (!dataItem) return;
    
      return (
        <>
          <h2>Details</h2>
          Name: {dataItem.company}
          <br />
          Ticker: {dataItem.ticker}
          <br />
          Stock Price: {dataItem.stockPrice}
        </>
      );
    }
    

    It accepts a dataItem prop, but then sets that value to its own internal state and then:

    • Only ever uses that internal state
    • Never updates that internal state

    Why is it duplicating state at all? If the goal is to rely on the prop, just use the prop:

    function Details({ dataItem }) {
      if (!dataItem) return;
      return (
        <>
          <h2>Details</h2>
          Name: {dataItem.company}
          <br />
          Ticker: {dataItem.ticker}
          <br />
          Stock Price: {dataItem.stockPrice}
        </>
      );
    }
    
    Login or Signup to reply.
  2. You are assigning the value to dataItem in Details.js only ONCE when you are rendering your component because you are setting it in useEffect with empty dependency array.

    To fix that you can put props.dataItem in the dependency array but it’s not a good solution for that.

    you actually dont need that seperate state.

    This is enough to make it work

    function Details({ dataItem }) {
      if (!dataItem) return null;
      
      return (
        <>
          <h2>Details</h2>
          Name: {dataItem.company}
          <br />
          Ticker: {dataItem.ticker}
          <br />
          Stock Price: {dataItem.stockPrice}
        </>
      );
    }
    

    also you don’t needed a defaultItem since you don’t want to display anything without dataItem

    Login or Signup to reply.
  3. Looking at your code sandbox, I realized you have a missing dependency in your useEffect.

    This is your actual useEffect:

    useEffect(() => {
        setDataItem(props.dataItem);
      }, []);
    

    If you are trying to make the useEffect run only on first render, you need to leave empty the square brackets ([]). In your case, you want setDataItem to run every change on dataItem, so you need to put the variable inside the square brackets. You can see those warnings on your code sandbox; or, if you are using VS Code, you can use the "ESLint" extension.

    Your useEffect after changes:

    useEffect(() => {
        setDataItem(props.dataItem);
      }, [props.dataItem]);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search