react input输入的时候输入一次就失去焦点,需要再次点击才能输入一次

如题,每次点击input的时候才能输入一次

查看了代码,原因应该是当我每次输入触发onChange的时候DOM重绘,但是根源并不清楚到底是什么,望指教;

因为是第一次用react,所以有什么问题大家也可以提出来,让我改进一下,谢谢!

代码如下
图片描述

class Goods extends Component {

    constructor() {
    super();
    this.state = {
        id: '',
        name: '',
        orderBy_id: 3,// 排序
        isFilter: false,
        type: '',//类型
        page_num: 1, // 页码
        min_price: '', // 最低价
        max_price: '', // 最高价
        screen_id: '', // 筛选选择类型
        str: ''
    };
    this.changeSort = this.changeSort.bind(this);
    this.changeProd = this.changeProd.bind(this);
    this.selectedAttr = this.selectedAttr.bind(this);
    this.resetAttr = this.resetAttr.bind(this);
    this.selectedFilter = this.selectedFilter.bind(this);
    this.changePrice = this.changePrice.bind(this);
    this.closeModal = this.closeModal.bind(this);
}
changePrice(event) {
    const target = event.target;
    if(target.name === 'min_price') {
        this.setState({
            min_price: event.target.value
        })
    }else {
        this.setState({
            max_price: event.target.value
        })
    }

}
 render() {
    const {data} = this.props;
    const SelectWrapper = () => {
        return (
            <TopWrapper>
                <TopItem className={(this.state.orderBy_id === 3 && !this.state.isFilter) ? 'selected' : ''}
                         onClick={(e) => this.changeSort(e, 'other', 3)}>
                    <span className='text'>综合</span>
                </TopItem>
                <TopItem className={(this.state.orderBy_id === 5 && !this.state.isFilter) ? 'selected' : ''}
                         onClick={(e) => this.changeSort(e, 'other', 5)}>
                    <span className='text'>销量</span>
                </TopItem>
                <TopItem
                    className={((this.state.orderBy_id === 2 || this.state.orderBy_id === 1) && !this.state.isFilter) ? 'selected' : ''}
                    onClick={(e) => this.changeSort(e, 'price')}>
                    <span className='text'>价格</span>
                    <span className='icon'>
                        <i className={`iconfont icon-shangjiantou ${this.state.orderBy_id === 2 ? 'selected' : ''}`}></i>
                        <br/>
                        <i className={`iconfont icon-xiajiantou ${this.state.orderBy_id === 1 ? 'selected' : ''}`}></i>
                    </span>
                </TopItem>
                <TopItem className={this.state.isFilter ? 'selected' : ''}
                         onClick={(e) => this.changeSort(e, 'shaixuan')}>
                    <span className='text'>筛选</span>
                    <span className='icon'>
                        <i className='iconfont'></i>
                        <br/>
                        <i className={`iconfont icon-xiajiantou ${this.state.isFilter ? 'selected' : ''}`}></i>
                    </span>
                </TopItem>
            </TopWrapper>
        )
    };
    const ProductContainers = () => {
        let isSelf = (type) => {
            if(type === '1') {
                return (
                    <span>自营</span>
                )
            }
            return null;
        };
        if(!data.length){
            return null
        }
        return (
            <ProductWrapper>{
                data.map((item, index) => {
                    return (
                        <ProductItem key={index}>
                            <div className='img'>
                                <img src={item.image} alt=""/>
                            </div>
                            <p className='name'>
                                {
                                    isSelf(item.support_type)
                                }
                                {item.name}
                            </p>
                            <p className='price'>¥
                                <span>
                                    {(item.price).toFixed(2)}
                                </span>
                                </p>
                        </ProductItem>
                    )
                })
            }
            </ProductWrapper>
        )

    };
    const FilterContainer = () => {
        const {isFilter, screen_id, min_price, max_price} = this.state;
        const {options} = this.props;
        if(isFilter) {
            return (
                <FilterWrapper>
                    <div className='content'>
                        <p className='title'>聚鲨服务</p>
                        <ul>
                            {
                                options.map((item, index) => {
                                    if(screen_id.indexOf(item.id) > -1) {
                                        return (
                                            <li key={index} onClick={() => {this.selectedAttr(item.id)}} className='screen-select'>{item.name}
                                                <img className='selected' src='http://wp.ghs.net/static/img/selectBg.png' alt=""/>
                                            </li>
                                        )
                                    }else {
                                        return (
                                            <li key={index} onClick={() => {this.selectedAttr(item.id)}}>{item.name}</li>
                                        )
                                    }
                                })
                            }
                        </ul>
                        <p className='title'>价格区间</p>
                        <p className='price-range'>
                            <input type="text" name='min_price' placeholder='最低价' onChange={this.changePrice} value={min_price} />
                            <span>-</span>
                            <input type="text" name='max_price' placeholder='最高价' onChange={this.changePrice} value={max_price}/>
                        </p>
                        <div className='buttons'>
                            <p className='reset' onClick={this.resetAttr}>重置条件</p>
                            <p className='sure' onClick={this.selectedFilter}>确定</p>
                        </div>
                    </div>
                    <div className='model' onClick={this.closeModal}></div>
                </FilterWrapper>
            )
        }
        return null
    };
    return (
        <Wrapper>
            <SelectWrapper/>
            <FilterContainer />
            <ProductContainers/>
        </Wrapper>
    )
}

}

阅读 15.9k
6 个回答

应该是在循环中的 key 值使用了 index 的缘故吧。
由于 React 中的 diff 算法需要通过 key 值判断前后的虚拟 dom 是否发生了改变,加上 index 的值会动态改变的缘故,所以会导致 dom 重绘。
之前,我在循环中产生了包含 inputdom 结构,并使用了时间戳作为 key 值出现了同样的情况。

任何情况下建议给 key 一个固定唯一的值。

I hope this will help you.

不要在你的render中
return的时候有分支判断。

比如你的if(isFilter). 这是一种不好的实践,并且很容易有各种问题,包括你的这个问题。

你现在相当于在render里又定义了3个子组件
把render里的组件<SelectWrapper/> <FilterContainer /> <ProductContainers/>
拿到外面去,或者把他们写成一个方法放Goods里


import React from 'react';
import {render} from 'react-dom';

const mountPoint = document.createElement('div');
mountPoint.setAttribute('id', 'root');
document.body.appendChild(mountPoint);


class Goods extends React.Component {
    constructor() {
        super();
        this.state = {
            id: '',
            name: '',
            orderBy_id: 3,// 排序
            isFilter: false,
            type: '',//类型
            page_num: 1, // 页码
            min_price: '', // 最低价
            max_price: '', // 最高价
            screen_id: '', // 筛选选择类型
            str: ''
        };
        this.changePrice = this.changePrice.bind(this);
    }

    changePrice(event) {
        const target = event.target;
        console.log(event.target.value)
        if(target.name === 'min_price') {
            this.setState({
                min_price: event.target.value
            })
        }else {
            this.setState({
                max_price: event.target.value
            })
        }
    }

    filterContainer() {
        const {isFilter, screen_id, min_price, max_price} = this.state;
        return (
            <div>
                <div className='content'>
                    <p className='title'>聚鲨服务</p>
                    <p className='title'>价格区间</p>
                    <p className='price-range'>
                        <input type="text" name='min_price' placeholder='最低价' onChange={this.changePrice} value={min_price} />
                        <span>-</span>
                        <input type="text" name='max_price' placeholder='最高价' onChange={this.changePrice} value={max_price}/>
                    </p>
                </div>
            </div>
        )
    };

    render() {
        return (
            <div>
                {this.filterContainer()}
                <p>min_price:{this.state.min_price}</p>
                <p>max_price:{this.state.max_price}</p>
            </div>
        )
    }
}


render(
    <Goods />,
    mountPoint
);
新手上路,请多包涵

请问楼主解决这个问题了么 我今天也遇到了

新手上路,请多包涵

这个原因是使用了高阶组件的原因,至于原因具体还不清楚,应该是修改状态的时候,重新执行render()方法,而你的输入框是写在高阶组件里面的,所以会导致重新执行你的高阶组件的那个方法,去重新渲染你的整个高阶组件,应该是react,diff算法的一个bug吧!

新手上路,请多包涵
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏