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

时间:2019-05-13 06:49:04

标签: javascript reactjs ref

我有5个输入元素的动态创建列表。现在,当我在React中单击一个“加号”图标元素(来自IonicIcons)时,我希望这些输入字段中的第一个成为焦点。

我的输入列表:

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

我的图标:

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

我可能应该将我的引用放在列表项上,但是,我猜对于每个新的列表元素,此引用都会被“覆盖”,因为我只有一个引用。我是否应该执行类似输入键查询之类的操作,以找出这是哪个列表键输入元素,并且如果它是第一个输入键索引,那么我将重点放在该输入元素上吗?

然后如何在设置showInputField值的toggleInput()方法中检索第一个输入元素?能否以某种方式要求输入元素的引用的props.key?

此组件是功能组件,我仅使用useRef ...

我的组件:

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

我的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

1 个答案:

答案 0 :(得分:0)

问题是您无法将ref从父组件传递到子组件。在新版本的react中,您可以使用forwardRef api来实现。如果您使用的是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();

快乐编码:)