Home > database >  React: Form not re-rendering when updated
React: Form not re-rendering when updated

Time:04-01

Disclaimer: I am new to React. I am trying to set up a form where selecting a different radio button at the top changes the list of checkboxes below to a different list, the text for which I've stored in four arrays within an object (formVersions). See code below for my setup. The radio buttons have an onClick function called radioButtonClick that puts together the component from the text in the corresponding array and sets the variable formList to this, and since I've put formList in the App() function that gets exported to the renderer, I would expect this to change the list of checkboxes on radio button click. However, it does not. The list is populated and rendered properly when radioButtonClick runs the first time on page load, but clicking on the radio buttons does not update the actual component on the page for whatever reason (though the function runs).

Not sure if my issue is due to something fundamental about how React works that I don't yet know, or some minor tweak that needs to be made. I am hoping for a solution that does not require that much reconfiguration, even if my method is not the typical way of doing this, but obviously that may end up not being possible. Thank you!

import './App.css';

var selectedVersion = 'metal-tearoff';

var formVersions = {
    'metal-tearoff': [
        'a',
        'b',
        'c'
    ],
    'metal-layover': [
        'd',
        'e',
        'f'
    ],
    'shingle-tearoff': [
        'a',
        'b',
        'c'
    ],
    'shingle-layover': [
        'd',
        'e',
        'f'
    ]
}

var formList = [];

function radioButtonClick(id) {
    selectedVersion = id;

    formList = [];
    for (var i = 0; i < formVersions[id].length; i  = 1) {
        formList.push(
            <div key={i.toString()}>
                <input type="checkbox" name={formVersions[id][i]} id={formVersions[id][i]} className = "checkbox" defaultChecked/>
                <label htmlFor={formVersions[id][i]}>{formVersions[id][i]}</label>
            </div>
        )
    }
}
radioButtonClick('metal-tearoff')

function App() {
  return (
    <div id = "main-div">
        <form onSubmit={() => {}} method="post" action="https://postman-echo.com/post">
            <input type="radio" name="roof-type" id="metal-tearoff" onClick= {() => {radioButtonClick('metal-tearoff')}} defaultChecked/>
            <label htmlFor="always">Metal Tearoff</label>

            <input type="radio" name="roof-type" id="metal-layover" onClick= {() => {radioButtonClick('metal-layover')}}/>
            <label htmlFor="never">Metal Layover</label>

            <input type="radio" name="roof-type" id="shingle-tearoff" onClick= {() => {radioButtonClick('shingle-tearoff')}}/>
            <label htmlFor="change">Shingle Tearoff</label>

            <input type="radio" name="roof-type" id="shingle-layover" onClick= {() => {radioButtonClick('shingle-layover')}}/>
            <label htmlFor="change">Shingle Layover</label>
            <div>
                {formList}
            </div>
            <div>
                <input type="submit" name="submit" value="Submit" />
            </div>
        </form>
    </div>
  );
}

export default App;

CodePudding user response:

Alex, your issue is in the way you are managing the state of your component. Think of your App function as a render function that React invokes many times (more times than you need to worry about in most cases). The variables and functions you have created outside of your App function do not ever change, while the App function gets called. In order to work with this, your App component has its own idea of state which you should manage. Hooks such as useState help you manage this very succinctly. I think of it like this: React decides to call your render (or functional component) function at its discretion, it will run through all of the code in your function. When it encounters a hook such as useState, it will reuse values that it saw before (unless the optional dependencies of the hook have changed in this invocation). Not sure if that helps you or not. Here is a working fork of your original:

https://codesandbox.io/s/react-form-question-1-forked-7qodq8?file=/src/App.js

CodePudding user response:

Yes, you are newbie React. You should watch more toturial and read document. I changed many line code for you

  1. All variales you need wrap it into Component( here is App Component )
  2. You research useState , useEffect and useMemo
  3. Here I setState selectedVersion , and I watched when selectedVersion changed, useMemo will run everytime when selectedVersion changed with params second of useMemo [selectedVersion],and the App will re-render

Hope help you ^^, If you code a lot, you will understand. Dont worry

import { useMemo, useState } from "react";
var formVersions = {
  "metal-tearoff": ["a", "b", "c"],
  "metal-layover": ["d", "e", "f"],
  "shingle-tearoff": ["a", "b", "c"],
  "shingle-layover": ["d", "e", "f"]
};
function App() {
  
  const [selectedVersion,setSelectedVersion]= useState("metal-tearoff")
  const renderFormList=useMemo(()=>{
    let formList = [];
    for (var i = 0; i < formVersions[selectedVersion].length; i  = 1) {
      formList.push(
        <div key={i.toString()}>
          <input
            type="checkbox"
            name={formVersions[selectedVersion][i]}
            id={formVersions[selectedVersion][i]}
            className="checkbox"
            defaultChecked
          />
          <label htmlFor={formVersions[selectedVersion][i]}>{formVersions[selectedVersion][i]}</label>
        </div>
      );
    }
    return formList;
  },[selectedVersion])
  function radioButtonClick(id) {
    setSelectedVersion(id)
  }
  return (
    <div id="main-div">
      <form
        onSubmit={() => {}}
        method="post"
        action="https://postman-echo.com/post"
      >
        <input
          type="radio"
          name="roof-type"
          id="metal-tearoff"
          onClick={() => {
            radioButtonClick("metal-tearoff");
          }}
          defaultChecked
        />
        <label htmlFor="always">Metal Tearoff</label>

        <input
          type="radio"
          name="roof-type"
          id="metal-layover"
          onClick={() => {
            radioButtonClick("metal-layover");
          }}
        />
        <label htmlFor="never">Metal Layover</label>

        <input
          type="radio"
          name="roof-type"
          id="shingle-tearoff"
          onClick={() => {
            radioButtonClick("shingle-tearoff");
          }}
        />
        <label htmlFor="change">Shingle Tearoff</label>

        <input
          type="radio"
          name="roof-type"
          id="shingle-layover"
          onClick={() => {
            radioButtonClick("shingle-layover");
          }}
        />
        <label htmlFor="change">Shingle Layover</label>
        <div>{renderFormList}</div>
        <div>
          <input type="submit" name="submit" value="Submit" />
        </div>
      </form>
    </div>
  );
}

export default App;
  • Related