React useRef not updating and rendering new values

10,746

Solution 1

From the React useRef() docs:

Keep in mind that useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render

So even though it is being updated, you will never get a re-render showing the 7th, 8th, etc. links that have been added.

I think you would be better off using useState() hook for your links and rendering those. Perhaps a separate question can identify the stale issues you were seeing.

Solution 2

You have to use both useState and useRef.

useRef for keeping the latest value and useState for updating the state.

Example :

const showARef = useRef("inline");
const showBRef = useRef("inline");

 const [showA, setshowA] = useState(showARef.current);
 const [showB, setshowB] = useState(showBRef.current);

Solution 3

You can use a state variable to re render all state components, a simple one which I have tried and have succeeded in doing is :

const [, forceUpdate] = useReducer((x) => x + 1, 0)

You can call forceUpdate() when you have added your links and it will function as useState()

Share:
10,746

Related videos on Youtube

Jpark9061
Author by

Jpark9061

Updated on May 26, 2022

Comments

  • Jpark9061
    Jpark9061 almost 2 years

    I'm a beginner React developer and I'm having an issue with this particular code snippet.

    Issues:

    1. Not all of the dummy data is being rendered even though I directly copied its value and rendered it as separate children
    2. When I click the add button to make a new input form, it doesn't get added to the render.

    I purposely chose to use useRef instead of useState because after the user adds or edit whatever links they want, I want to send keyRef to a NoSQL database; whereas when I used useState() it was giving me stale state issues, where the array with all the links were not updated constantly.

    Any suggestions? Please and thank you!

    CodeSandbox link: https://codesandbox.io/s/react-hooks-counter-demo-forked-0bjdy?file=/src/index.js

    App.js

    import React, { useState, useRef } from "react";
    import ReactDOM from "react-dom";
    import { links } from './links';
    
    import "./styles.css";
    
    function App() {
      const [loaded, setLoaded] = useState(false);
      const formRef = useRef([]);
      const keyRef = useRef([]);
    
      if (!loaded) {
        keyRef.current = links;
        links.forEach(link => RenderLinks(link.id));
        setLoaded(true);
      }
    
      function RenderLinks(id) {
        const formLength = formRef.current.length;
    
        if (id === null)
        formRef.current = [ ...formRef.current, <AddLink key={formLength} id={formLength} /> ];
    
        if (id && !formRef.current.find(form => form.props.id === id))
        formRef.current = [ ...formRef.current, <AddLink key={formLength} id={formLength} /> ];
      }
    
      function AddLink(props) {
        const id = props.id;
        const value = keyRef.current[id] ? keyRef.current[id].link : '';
        const [input, setInput] = useState(value);
        keyRef.current = [
          ...keyRef.current,
          {
            id: id,
            link: '',
          }
        ];
        return <input onChange={e => setInput(e.target.value)} value={input} />
      }
    
      return (
        <div>
          <button onClick={() => RenderLinks(null)}>add</button>
          {formRef.current ? formRef.current.map(child => child) : null}
        </div>
      )
    }
    

    links.js aka dummy data

    export const links = [
      {
        id: 0,
        link: "www.zero.com"
      },
      {
        id: 1,
        link: "www.one.com"
      },
      {
        id: 2,
        link: "www.two.com"
      },
      {
        id: 3,
        link: "www.three.com"
      },
      {
        id: 4,
        link: "www.four.com"
      },
      {
        id: 5,
        link: "www.five.com"
      },
      {
        id: 6,
        link: "www.six.com"
      },
      {
        id: 7,
        link: "www.seven.com"
      }
    ];
    
    
    • Caleb Taylor
      Caleb Taylor over 3 years
      when you click add, where's the value coming from? I'm not sure because I see 6 inputs
    • Jpark9061
      Jpark9061 over 3 years
      Hey! You're adding another input box. so that would make it 7 inputs. The values of the input box will later be stored in keyRef and to Firebase, which I haven't added in the code snippet.