20

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

2
  • when you click add, where's the value coming from? I'm not sure because I see 6 inputs Commented Aug 30, 2020 at 0:03
  • 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. Commented Aug 30, 2020 at 0:06

3 Answers 3

18

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.

Sign up to request clarification or add additional context in comments.

Comments

9

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

1 Comment

6

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.