How to set react ref in a for loop

I have a 'fileUpload' component which I am passing into a form in my React App.

I want to have the ability to set a unique ref for each input element in my for loop and then pass this ref to a delete button to remove the file.

FileUploadComponent

const FileUpload = ({ addFile, runClick }) => {
          const uploadButton = [];
          const myRefs = React.useRef([]);
        
          for (let i = 1; i < 6; i += 1) {
            uploadButton.push(
              <div key={i}>
                <input
                  type="file"
                  id={`file${i}`}
                  ref={myRefs.current[i] ?? React.createRef()}
                  name={`file${i}`}
                  onChange={addFile}
                />
                <RemoveButton type="button" onClick={() => removeFile()}>
                  X button{i}
                </RemoveButton>
              </div>
            );
          }
    
      return uploadButton;
    };
    
    export default FileUpload;

FormComponent

//working without using the FileUploadComponent and setting/passing the ref manually

<InputField className="col">
        <input
          type="file"
          id="file3"
          name="file3"
          ref={ref3}
          onChange={addFile}
        />
        <RemoveButton type="button" onClick={() => removeFile(ref3)}>
          X
        </RemoveButton>
      </InputField>

// trying to have the ref be automatically assigned and passed to delete button

<InputField className="col">
    <FileUpload addFile={addFile} runClick={() => removeFile()} />
  </InputField>

Upvotes: 0

Views: 625

Answers (2)

adong Xiao
adong Xiao

Reputation: 1

if you don't know how many ref will be defined, you should use RefCallback

there is its type definition in React

type RefCallback<T> = { bivarianceHack(instance: T | null): void  }["bivarianceHack"];
type Ref<T> = RefCallback<T> | RefObject<T> | null;

the RefCallback can pass a instance to you, and then you can use only one React ref to hold all children componends' ref, e.g.

function Parent(){
  const attachmentRefs = useRef({});
  
  return <>
    <Child ref={(instance)=>{
        // before hold the instance, you can check the attachmentRefs.current first.
        //  so that the variable name can be determined in advance
        attachmentRefs.current.childA = instance
        }} />
    <Child ref={(instance)=>{
        // same logic as last one
        attachmentRefs.current.childB = instance
    }} />
    </>
}

Upvotes: 0

T J
T J

Reputation: 43156

You can create an array of refs before the loop, using Array.fill():

const myRefs = useRef(new Array(6).fill(createRef()));

And use it in the loop like:

<input type="file" ref={myRefs[i]}/>

Upvotes: 1

Related Questions