title: How to immediately rerender child component after updating the sessionStorage using custom hook
body: <p>My goal is to build a simple product review system using React, Next.JS and the browser's sessionStorage.
  The user should be able to click on a button to &quot;Add a review&quot;. This action will trigger the display of a text area and a submit button. Once the user click the submit button, the review content should be persisted in the sessionStorage and <strong>immediately showed up in a list of reviews.</strong></p>
  <p><a href="https://i.stack.imgur.com/mKqtn.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/mKqtn.png" alt="submit review prototype" /></a></p>
  <p><strong>My problem is that although I can update the sessionStorage after submitting the review, the app is not displaying the list of existing reviews right away.</strong>
  If I leave the page and get back, the reviews will be shown up, meaning my custom hook seems to be working fine.</p>
  <p>Here's the ReviewForm.tsx code:</p>
  <pre><code>export const ReviewForm: React.FC&lt;Props&gt; = ({ productId }): JSX.Element =&gt; {
    const [showForm, setShowForm] = useState&lt;boolean&gt;(false);
    const [storedValues, setStoredValues] = useSessionStorage&lt;SessionStorage[]&gt;(
      &quot;products-reviews&quot;,
      []
    );
  
    const registerReview = (event: any) =&gt; {
      event.preventDefault();
      const reviewText = event.target.review.value;
      const productIndex = storedValues?.findIndex(
        (review) =&gt; review.productId === productId
      );
  
      if (productIndex === -1 || productIndex === undefined) {
        setStoredValues([...storedValues!, { productId, reviews: [reviewText] }]);
      } else {
        const reviews = [...storedValues![productIndex].reviews, reviewText];
        const updatedReviews = [...storedValues!];
        updatedReviews[productIndex].reviews = reviews;
        setStoredValues(updatedReviews);
      }
  
      setShowForm(false);
    };
  
    return (
      &lt;div className={styles.reviewsContainer}&gt;
        &lt;button
          className={styles.addReviewButton}
          onClick={() =&gt; setShowForm(true)}
        &gt;
          &lt;span&gt;Add a review&lt;/span&gt;
        &lt;/button&gt;
        {showForm &amp;&amp; (
          &lt;form
            className={styles.reviewForm}
            onSubmit={(event) =&gt; registerReview(event)}
          &gt;
            &lt;textarea className={styles.reviewInput} name=&quot;review&quot; required /&gt;
            &lt;button className={styles.reviewSubmitButton} type=&quot;submit&quot;&gt;
              Submit
            &lt;/button&gt;
          &lt;/form&gt;
        )}
        &lt;ReviewList productId={productId} /&gt;
      &lt;/div&gt;
    );
  };
  
  </code></pre>
  <p>And here's the ReviewList.tsx component, rendered inside ReviewForm.tsx:</p>
  <pre><code>export const ReviewList: React.FC&lt;Props&gt; = ({ productId }): JSX.Element =&gt; {
    const [reviews, _] = useSessionStorage&lt;SessionStorage[]&gt;(
      &quot;products-reviews&quot;,
      []
    );
  
    const productReviews = reviews?.find(
      (review) =&gt; review.productId === productId
    )?.reviews;
  
    return (
      &lt;ul&gt;
        {productReviews?.map((review) =&gt; (
          &lt;li key={Math.random() * 10000}&gt;{review}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
    );
  };
  
  </code></pre>
  <p>Lastly, here's my custom hook useSessionStorage:</p>
  <pre><code>export const useSessionStorage = &lt;T&gt;(
    key: string,
    initialValue?: T
  ): SessionStorage&lt;T&gt; =&gt; {
    const [storedValue, setStoredValue] = useState&lt;T | undefined&gt;(() =&gt; {
      if (!initialValue) return;
      try {
        const value = sessionStorage.getItem(key);
        return value ? JSON.parse(value) : initialValue;
      } catch (error) {
        return initialValue;
      }
    });
  
    useEffect(() =&gt; {
      if (storedValue) {
        try {
          sessionStorage.setItem(key, JSON.stringify(storedValue));
        } catch (error) {
          console.log(error);
        }
      }
    }, [storedValue, key]);
  
    return [storedValue, setStoredValue];
  };
  
  </code></pre>
  <p>The title of my question says &quot;how to rerender <strong>child component</strong>&quot; because I noticed if I completely delete the ReviewList.tsx component, bringing all its render logic inside the ReviewForm.tsx, my application will behave as expected.</p>
  <p>So maybe the problem is related with this relation between components?</p>
  <p>Any advice is welcome.</p>