How to deal with a ref within a loop?

前端 未结 4 1541
北恋
北恋 2021-02-12 22:13

Below is my parent component with multiple inputs from a loop. How can I choose one input to focus? Do I have to create a dynamic ref in this case?

相关标签:
4条回答
  • 2021-02-12 22:50

    Using a general useFocus hook

    // General Focus Hook
    const useFocus = (initialFocus = false, id = "") => {
        const [focus, setFocus] = useState(initialFocus)
        return ([
            (newVal=true) => setFocus(newVal), {
                autoFocus: focus,
                key: `${id}${focus}`,
                onFocus: () => setFocus(true),
                onBlur: () => setFocus(false),
            },
        ])
    }
    
    const data: [{
            name: "abc"
        },{ 
            name: "def" 
    }]
    
    const TestRef = () => {
    
        const focusHelper = data.map( (_,i) => {
            const [setFocus, focusProps]= useFocus(false, i)
            return {setFocus, focusProps}
        }) 
    
        return (
          <div>
            {data.map( (o,i) => (
              <Hello placeholder={o.name} {...focusHelper[i].focusProps} />;
            ))}
            <button onClick={() => focusHelper[0].setFocus()}>focus input 1</button>
            <button onClick={() => focusHelper[1].setFocus()}>focus input 2</button>
          </div>
        );
    }
    

    You can find more info here: Set focus on input after render

    0 讨论(0)
  • 2021-02-12 23:00

    You can use callback refs to generate and store the dynamic ref of each input in an array. Now you can refer to them using the index of the ref:

    const Hello = React.forwardRef((props,  ref) => <input ref={ref} />);
    
    class Button extends React.Component {
      onClick = () => this.props.onClick(this.props.id);
    
      render() {
        return (
          <button onClick={this.onClick}>{this.props.children}</button>
        );
      }
    }
    
    class TestRef extends React.Component {
      state = {
        data: [
          {
            name: "abc"
          },
          { name: "def" }
        ]
      };
      
      inputRefs = [];
      
      setRef = (ref) => {
        this.inputRefs.push(ref);
      };
      
      focusInput = (id) => this.inputRefs[id].focus();
      
      render() {
        return (
          <div>
            {this.state.data.map(({ name }) => (
              <Hello 
                placeholder={name} 
                ref={this.setRef} 
                key={name} />
            ))}
            <Button onClick={this.focusInput} id={0}>focus input 1</Button>
            <Button onClick={this.focusInput} id={1}>focus input 2</Button>
          </div>
        );
      }
    }
    
    ReactDOM.render(<TestRef />, document.getElementById("root"));
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    
    <div id="root"></div>

    0 讨论(0)
  • 2021-02-12 23:04

    I discovered another way of tackling this:

    let dataCount = 0;
    
    class TestRef extends React.Component {
      state = {
        data: [
          {
            name: "abc"
          },
          { name: "def" }
        ]
      };
      focusInput = (thisHello) => this[`ref${thisHello}`].current.focus();
      render() {
        return (
          <div>
            {this.state.data.map(o => {
              dataCount++
              return <Hello placeholder={o.name} ref={(el) => { this[`ref${dataCount}`] = el; }} />;
            })}
            <button onClick={() => this.focusInput(1)}>focus input 1</button>
            <button onClick={() => this.focusInput(2)}>focus input 2</button>
          </div>
        );
      }
    }
    

    The dataCount is unnecessary if your Hello element has a key or unique ID to use as a variable.

    0 讨论(0)
  • 2021-02-12 23:06

    if you are coming to this question 2020 here is how you create multiple refs using create hooks in a loop

       const MyComponent=(){
        // empty list to put our refs in
        let LiRefs = []
    
        return (
            <React.Fragment>
              <ul className="event-list">
    // this part i am checking if my data exist first other wise load spinner 
                {newData ? (
                  newData.map((D) => {
    // the cool part inside the loop 
    //create new ref 
    //push it into arr 
    
                    const newRef = createRef();
                    LiRefs.push(newRef);
                    return (
    // link it to ur li 
    // voila you have list of refs that points to your list items 
                      <li key={D._id} ref={newRef}>
                        title : {D.title} <br />
                        description : {D.description}
                        <br />
                        data : {D.date} <br />
                        price : {D.price}
                        <br />
                        <div>creator : {D.creator.username}</div>
                        {authData.token && (
                          <button type="button" id={D._id} onClick={handelBooking}>
                            Book
                          </button>
                        )}
                      </li>
                    );
                  })
                ) : (
                  <Spinner />
                )}
              </ul>
            </React.Fragment>
          );
     }
    
    0 讨论(0)
提交回复
热议问题