反应-在完全不同的组件上调用setState时,输入会失去焦点

时间:2019-10-12 06:01:00

标签: javascript reactjs react-redux

我是React的初学者,仍在学习过程中,请多多包涵。我的React应用出现问题,因为输入一个字母后输入内容失去了焦点。我已经将文本字段单独分解为一个组件。但是,当我在其他组件中的元素上调用setState时,似乎会导致该问题。

在一个大组成部分DropdownTextComponent下,我有三个组成部分DisplayedColumnsListAvailableColumnsListDropdownComponent

这是我的DropdownComponent,其中包含三个不同的组件。

const DropdownComponent = (props) => {
    return (
        <div className = "dropdown-column">
            <Dropdown
                isOpen = {this.state.dropdownOpen}
                onClose = {() => this.setOpen(false)}
            >
                {props.dropdownsearch}
                {props.displayedcolumns}
                {props.availablecolumns}
            </Dropdown>
        </div>
    );
}

这是我的DropdownTextComponent

const DropdownTextComponent = () => {
    return (
        <div className = "dropdown-text-input">
            <TextInput
                onChange = {this.dropdownSearch}
                value = {this.state.dropdownValue}
            >
            </TextInput>
        </div>
    )
}

这是方法dropdownSearch,称为onChange

dropdownSearch(e) {
    this.state.dropdownValue = e.target.value;
    let resultCols = this.state.columns;
    let dropdownSearchList = []

    let dropdownSet = new Set();
    for (let i = 0; i < resultCols.length; i++) {
        if (resultCols[i].text.includes(e.target.value)) {
            dropdownSet.add(resultCols[i]);
        }
    }
    dropdownSearchList = [...dropdownSet]
    this.setState({
        toggleColumnList : dropdownSearchList
    })
}

现在toggleColumnList用于两个不同的组件DisplayedColumnsListAvailableColumnsList中,因此我假设在此处使用setState时,不应重新渲染DropdownTextComponent。但是这样做,我的输入字段失去了焦点。我已将setState部分注释掉,并且工作正常。

我想知道问题出在哪里以及如何解决。如果您需要更多信息,请告诉我。

1 个答案:

答案 0 :(得分:0)

像这样的东西可以更好地工作?

class App extends React.Component {
    constructor (props) {
        super(props)
        this.state = {
            toggleColumnList: []
            dropdownValue: '',
            columns: [  { text: 'some text'}, { text: 'some other text'} ]
        }
    }

    dropdownSearch = (e) => {
        const value = e.target.value;
        let resultCols = this.state.columns;
        let dropdownSearchList = []

        let dropdownSet = new Set();
        for (let i = 0; i < resultCols.length; i++) {
            if (resultCols[i].text.includes(e.target.value)) {
                dropdownSet.add(resultCols[i]);
            }
        }
        dropdownSearchList = [...dropdownSet]
        this.setState({
            dropdownValue: value,
            toggleColumnList : dropdownSearchList
        })
    }

    render () {
        const { columns, toggleColumnList, dropdownValue } = this.state
        return (
            <DropdownComponent>
                <DropdownTextComponent value={dropdownValue} onChange={this.dropdownSearch}/>
                <DisplayedColumnsList columns={toggleColumnList.length ? toggleColumnList : columns} />
                <AvailableColumnsList columns={toggleColumnList.length ? toggleColumnList : columns} />
            </DropdownComponent>
        )
    }
}

class DropdownComponent extends React.Component {
    constructor (props) {
        super(props)
        this.state = {
            isOpen: true
        }
    }
    close = () => {
        this.setState({
            isOpen: false
        })
    }
    render () {
        return (
            <div className = "dropdown-column">
                <Dropdown
                    isOpen={this.state.isOpen}
                    onClose={this.close}
                >
                { props.children }
                </Dropdown>
            </div>
        )
    }
} 

const DropdownTextComponent = (props) => {
    const { onChange, value } = props
    return (
        <div className = "dropdown-text-input">
            <TextInput
                onChange={onChange}
                value={value}
            />
        </div>
    )
}

更新
通常,我试图想象您的组件结构如何。

主要要点是希望您的DropdownTextComponent仅在其值或其更改事件处理程序更改时才呈现。
对于这种情况,您应该避免每次渲染DropdownComponent时都像以前那样显式渲染它,但是让React为您处理重新渲染。

当您执行类似props={ <DropdownTextComponent /> }的操作时,括号内的表达式会在组件的每次渲染时立即求值。此外,您没有将任何内容传递给子组件。
但是,如果您这样做<DropdownComponent><DropdownTextComponent value={value} onChange={onChange} /></DropdownComponent>,React将解析您App的整个结构,并仅在其属性或状态改变时才渲染每个节点。

为此,由于父级是自定义组件,因此您必须在其render方法中显式添加其子级。您可以使用特殊的React道具children来完成此任务,该道具包含您已定义为组件后代的所有内容。