title: Why is my React component rendering twice?
body: <p>I'm using <code>React-hooks</code> and the <code>Context API</code> for state management. I've console logged out the <code>context</code> state when the <code>consumer</code> component renders. In the <code>console</code> I noticed that the state from the <code>context</code> gets logged out twice. Why is that? </p>
  
  <p>I'm using the <code>fetch API</code> to pull in data from my local <code>node</code> server. So, in the first few lines of the <code>console</code> I get the initial state of the <code>context</code> e.g <code>undefined</code>, <code>null</code> - then JUST below that, I get the updated state with the data pulled in from the server. </p>
  
  <p>I've created a "Master" <code>context</code> to share <code>functions</code> that I'll use throughout the app. The <code>fetch</code> function is using <code>async/await</code>:</p>
  
  <pre><code>
  import React, { Component, createContext } from 'react';
  
  export const MasterContext = createContext();
  
  export class MasterProvider extends Component {
      state = {
          fetchData: async (url) =&gt; {
              let res = await fetch(url);
              let data = await res.json();
              return data;
          }
      }
  
      render() { 
  
          return ( 
              &lt;MasterContext.Provider value={{...this.state}}&gt;
                  {this.props.children}
              &lt;/MasterContext.Provider&gt;
           );
      }
  }
  
  
  
  </code></pre>
  
  <p>I've got two components, using two different <code>contexts</code> - one <code>context</code> is real simple</p>
  
  <pre><code>
  state = {
          title: '',
          body: '',
          cta: {
              text: ''
          },
          img: '',
          setHeaderPromo: (res) =&gt; {
              this.setState({
                  title: res[0].title,
                  body: res[0].body,
                  cta: {...this.state.cta, ...res[0].cta},
                  img: res[0].img
              });
          }
      }
  
  </code></pre>
  
  <p>The data being pulled in for this component is just a simple <code>array</code> with a single <code>object</code>. </p>
  
  <p>This is the <code>consumer</code> component:</p>
  
  <pre><code>
  const HeaderPromo = () =&gt; {
      const {title, body, cta, img, setHeaderPromo} = useContext(HeaderContext);
      const {fetchData} = useContext(MasterContext);
  
      useEffect(() =&gt; {
  
          fetchData(`http://localhost:5000/api/header`)
              .then((res) =&gt; {
                  setHeaderPromo(res);
          });
      }, [fetchData, setHeaderPromo]);
  
      console.log(title);
  
      return ( 
          &lt;article className="cp-header__promo"&gt;
              &lt;div className="cp-header__promo__image"&gt;
                  &lt;img src={img} alt="promo"/&gt;
              &lt;/div&gt;
              &lt;div className="cp-header__promo__copy"&gt;
                  &lt;h3&gt;{title}&lt;/h3&gt;
                  &lt;p&gt;{body}&lt;/p&gt;
                  &lt;button&gt;{cta.text}&lt;/button&gt;
              &lt;/div&gt;
          &lt;/article&gt;
       );
  }
  
  </code></pre>
  
  <p>So, this technically works. However, I noticed that when I log out the <code>title</code> variable, it gets output twice. The first time it's the initial state of the <code>context</code>, the second time, it outputs the contents of the data. Why is it doing that?</p>
  
  <p>My problem is with my second component - the <code>context</code> state is just an empty <code>array</code> that gets filled after the <code>fetch</code> request.</p>
  
  <p>The second <code>context</code>:</p>
  
  <pre><code> state = {
          albums: null,
          setNewReleases: (res) =&gt; {
              this.setState({
                  albums: res
              });
  
          }
      }
  
  </code></pre>
  
  <p>These are the two <code>consumer</code> components:</p>
  
  <pre><code>const NewReleases = () =&gt; {
  
      const {albums, setNewReleases} = useContext(NewReleaseContext);
      const {fetchData} = useContext(MasterContext);
  
      useEffect(() =&gt; {
  
          fetchData(`http://localhost:5000/api/new-releases`)
              .then((res) =&gt; {
                  setNewReleases(res);
              });
  
      }, [fetchData, setNewReleases]);
  
    console.log('from newRelease component', albums);
  
      return ( 
          &lt;section className="cp-new-releases"&gt;
              &lt;Row sectionHeading={`New Releases`} albums={albums}/&gt;
          &lt;/section&gt;
       );
  }
  
  export default NewReleases;
  
  </code></pre>
  
  <p>So, again, the <code>albums</code> variable gets logged out twice. first, the initial state, then the data gets pulled in, and it logs it again.</p>
  
  <p>Now, I'm passing this <code>albums</code> variable down to the <code>&lt;Row/&gt;</code> component as a <code>prop</code>.</p>
  
  <p>Row component:</p>
  
  <pre><code>const Row = ({sectionHeading, albums}) =&gt; {
  
      console.log('from row component', albums);
  
      return ( 
          &lt;Fragment&gt;
              &lt;div className="cp-new-releases__row"&gt;
              {(sectionHeading) &amp;&amp; (&lt;h3 className="row-title"&gt;{sectionHeading}&lt;/h3&gt;)}
                  &lt;div className="cp-new-releases__row__album-container"&gt;
  
                  {albums.map((item, index) =&gt; (
                          &lt;Album img={item.img} title={item.title} key={index}/&gt;
                    ))}
  
                  &lt;/div&gt; 
              &lt;/div&gt;
          &lt;/Fragment&gt;
       );
  }
  
  export default Row;
  
  </code></pre>
  
  <p>Now the <code>albums</code> variable is an <code>array</code> containing two <code>objects</code>. If I try to loop through the <code>array</code>, its throws the error <code>Uncaught TypeError: Cannot read property 'map' of null</code>.</p>
  
  <p>The only way I can get around this is by doing an <code>if</code> check to see if <code>albums</code> holds a value.</p>
  
  <pre><code>
  const Row = ({sectionHeading, albums}) =&gt; {
  
      console.log('from row component', albums);
  
      return ( 
          &lt;Fragment&gt;
              &lt;div className="cp-new-releases__row"&gt;
              {(sectionHeading) &amp;&amp; (&lt;h3 className="row-title"&gt;{sectionHeading}&lt;/h3&gt;)}
                  &lt;div className="cp-new-releases__row__album-container"&gt;
                    {(albums) ? (
                      albums.map((item, index) =&gt; (
                          &lt;Album img={item.img} title={item.title} key={index}/&gt;
                    ))
                    ) : (&lt;p style={{color: 'red'}}&gt;no album&lt;/p&gt;)}
                  &lt;/div&gt; 
              &lt;/div&gt;
          &lt;/Fragment&gt;
       );
  }
  
  export default Row;
  
  </code></pre>
  
  <p>It's trying to loop through the initial state of the <code>context</code>. Can someone explain whats going on, and how I can improve my code?</p>
  
  <p>I know this was long-winded. So, if you made it to the end, you're a champ.</p>
  
  <p>Thanks</p>