Jpark9061
Jpark9061

Reputation: 1080

React useRef not updating and rendering new values

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"
  }
];

Upvotes: 19

Views: 43945

Answers (3)

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);

Upvotes: 6

Arya Bhivpathaki
Arya Bhivpathaki

Reputation: 101

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()

Upvotes: 9

Anthony
Anthony

Reputation: 6482

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.

Upvotes: 18

Related Questions