简体   繁体   English

React:通过引用访问动态创建的元素的属性

[英]React: Access properties of dynamically created elements by refs

I have a dynamically created list of 5 input elements. 我有5个输入元素的动态创建的列表。 When I now click on a "plus" icon element (from IonicIcons) in React, I want the first of those input fields to be focused. 现在,当我在React中单击一个“加号”图标元素(来自IonicIcons)时,我希望这些输入字段中的第一个成为焦点。

My input List: 我的输入清单:

if (actualState.showInputField === true) {
            inputField = (
            <div>       
                {                    
                    actualState.inputFields.map((val,index) => (   
                        <ListElemErrorBoundary key={index}>                   
                            <InputElement key={index} elemValue = {val} name={"input" +  index} onChangeListener={(event) => handleDoublettenIDs(event,index)} />
                        </ListElemErrorBoundary>  
                        )
                    )
                }                
                {actualState.errorMessage!= '' ? <Alert color="danger" >{actualState.errorMessage}</Alert> : null}
                {actualState.successMessage !='' ? <Alert color="success" >{actualState.successMessage}</Alert> : null} 
                <br />                    
                <p><button onClick = { () =>  {
                    handleInputs(props.anzeigeID);    
                    vanishMessage();                
                    }                
                }>absenden</button></p>   
            </div>  
            )
        }
        return inputField;
    }

My Icon: 我的图示:

const checkIcon = () => {
        let showIcon = null;
        if (actualState.showInputField === false) {
            showIcon = (
               <IoIosAddCircleOutline ref={toggleSignRef} onClick = {toggleInput}
                />
            )
        } else {
            showIcon = (
                <IoIosRemoveCircleOutline onClick = {toggleInput}
                />
            )
        }
        return showIcon;
    }

I probably should place my ref on the list items, however, I guess that for every new list element, this ref gets "overwritten" because I have only one ref. 我可能应该将我的引用放在列表项上,但是,我猜对于每个新的列表元素,此引用都会被“覆盖”,因为我只有一个引用。 Should I do something like a input key query, to find out which list key input element this is, and if it is the first input key index, I execute a focus on that input element? 我是否应该执行类似输入键查询的操作,以找出这是哪个列表键输入元素,并且如果它是第一个输入键索引,那么我应该对该输入元素执行聚焦吗?

And how then can I retrieve the first input element inside the method toggleInput() where I set the showInputField value? 然后,如何设置方法showInputField的toggleInput()方法中的第一个输入元素呢? Is it somehow possible to ask for the props.key of that input element's reference? 是否可以通过某种方式要求输入元素引用的props.key?

This component is a functional component and I use useRef only... 该组件是功能组件,我仅使用useRef ...

My Component: 我的组件:

import React, {useState, useRef, useEffect} from "react";
import { IoIosAddCircleOutline } from 'react-icons/io';
import { IoIosRemoveCircleOutline } from 'react-icons/io';
import InputElement from './inputElementDublette';
import fetch from 'isomorphic-unfetch';
import getConfig from 'next/config';
import ListElemErrorBoundary from './ListElemErrorBoundary';
import { Button, Alert  } from 'reactstrap';

let url_link;
let port = 7766; 

const { serverRuntimeConfig, publicRuntimeConfig } = getConfig();
const apiUrl = publicRuntimeConfig.apiUrl; //|| publicRuntimeConfig.apiUrl;
const server = publicRuntimeConfig.SERVERNAME;

let doublettenListe_link = `http://${server}:${port}/doubletten/`;


//functional component with state, with useState
const DubletteComponent = props => {
    const toggleSignRef = useRef();

    const [actualState, changeState] = useState({
        showInputField: false,
        dublettenIDs: [],
        errorMessage: '', 
        successMessage: '',  
        inputFields: ['','','','',''],                
        visible : false,
    });    


    const toggleInput = () => {
        changeState({...actualState, showInputField: !actualState.showInputField});
    }

    const vanishMessage = ()=>{    
          window.setTimeout(() => {
            changeState({
                ...actualState,
                errorMessage:'',
                successMessage: '',        
            });
          },7000);
      }


    const handleDoublettenIDs = (event,index) => { 
        let idnumber = event.target.value;
        let newInputFields = [...actualState.inputFields];
        newInputFields.splice(index,1, idnumber);
        //console.log("new:",newInputFields);
        if (isNaN(idnumber)) {
            changeState({...actualState, errorMessage: 'ID is not a number'})
        } if (idnumber > 2147483647) {
            changeState({...actualState, errorMessage: 'Number can not be bigger than 2147483647!'})
        }        
        else {
            changeState({...actualState, inputFields: newInputFields, errorMessage: '' });
        }      
    }

    const handleInputs = (anzeigeID) => {
        if (process.browser && apiUrl==='dev') {
            doublettenListe_link = `http://localhost:${port}/doubletten/`;
        }
        if (actualState.errorMessage=='') {
            let array = actualState.inputFields;
            let filtered = array.filter(function(el) {
                return el != '';
            });                                   
            const requestOptions = {
                method: 'POST',
                headers: {'Accept': 'application/json', 'Content-Type':'application/json'},            
                body: JSON.stringify({
                    id: anzeigeID,
                    dublettenIDs: filtered
                })
            };
                //console.log("inputfields:",filtered);
              // Note: I'm using arrow functions inside the `.fetch()` method.
              // This makes it so you don't have to bind component functions like `setState`
              // to the component.
              //console.log("link:", doublettenListe_link);
            fetch(doublettenListe_link , requestOptions)
            .then((response) => { 
                //console.log("Resp:", response);
                let tempArray = ['','','','',''];
                changeState({...actualState, inputFields: tempArray});   
                //console.log(actualState);        
                changeState({...actualState, dublettenIDs: []});  
                changeState({...actualState, successMessage: `Doubletten-IDs wurden erfolgreich eingetragen!`});

                return response;          
            }).catch((error) => {
                changeState({...actualState, errorMessage: `Error beim Eintrage der Dubletten. Bitte prüfen, ob der Server läuft. Error: ${error.statusText}`});
            });  
        }       
    }

    const checkIcon = () => {
        let showIcon = null;
        if (actualState.showInputField === false) {
            showIcon = (
               <IoIosAddCircleOutline onClick = {toggleInput}
                />
            )
        } else {
            showIcon = (
                <IoIosRemoveCircleOutline onClick = {toggleInput}
                />
            )
        }
        return showIcon;
    }

    const checkPrerequisites = () => {
        //let errorMessage = '';
        let inputField = null;
        // if (actualState.errorMessage != '') {
        //     errorMessage = (
        //         <Alert color="danger">{actualState.errorMessage}</Alert>
        //     )
        // }        

        //Outsourcing check for variable and return JSX elements on conditionals
        if (actualState.showInputField === true) {
            inputField = (
            <div>       
                {                    
                    actualState.inputFields.map((val,index) => (   
                        <ListElemErrorBoundary key={index}>                   
                            <InputElement key={index} elemValue = {val} name={"input" +  index} onChangeListener={(event) => handleDoublettenIDs(event,index)} />
                        </ListElemErrorBoundary>  
                        )
                    )
                }                
                {actualState.errorMessage!= '' ? <Alert color="danger" >{actualState.errorMessage}</Alert> : null}
                {actualState.successMessage !='' ? <Alert color="success" >{actualState.successMessage}</Alert> : null} 
                <br />                    
                <p><button onClick = { () =>  {
                    handleInputs(props.anzeigeID);    
                    vanishMessage();                
                    }                
                }>absenden</button></p>   
            </div>  
            )
        }
        return inputField;
    }

        return (            
            <div >
                {checkIcon()}  Dubletten eintragen   

                {checkPrerequisites()}                     


            </div>                               
        )      
    }

export default DubletteComponent

My InputElement Component: 我的InputElement组件:

const inputElement = (props) => (
    <p>
        <input 
            ref={props.ref}
            value ={props.elemValue}
            name={props.name}
            type="number" 
            max="2147483647"
            placeholder="Doubletten-ID" 
            onChange={props.onChangeListener}>            
        </input>
    </p>


)    

export default inputElement

The issue is you can not pass ref from your parent component to child component. 问题是您无法将ref从父组件传递到子组件。 In new version of react you can achieve this by using forwardRef api. 在新版本的react中,您可以使用forwardRef api来实现。 Use it like below if you are in react @16 version. 如果您使用的是React @ 16版本,请像下面一样使用它。

import React from 'react'

const inputElement = React.forwardRef(props) => (
    <p>
        <input 
            ref={props.ref}
            value ={props.elemValue}
            name={props.name}
            type="number" 
            max="2147483647"
            placeholder="Doubletten-ID" 
            onChange={props.onChangeListener}>            
        </input>
    </p>
)  

//To focus textinput

this.inputref.focus();

Happy coding :) 快乐的编码:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM