美文网首页
受控组件

受控组件

作者: 灯火葳蕤234 | 来源:发表于2019-05-02 15:20 被阅读0次
    class Counters extends Component {
        state = { 
            counters: [
                { id: 1,value: 4 },
                { id: 2,value: 0 },
                { id: 3,value: 0 },
                { id: 4,value: 0 }
            ]
        }
        handleReset = () => {
            const counters = this.state.counters.map(c => {
                c.value = 0;
                return c;
            })
            this.setState({ counters });
        }
        handleDelete = (counterId) => {
            const counters = this.state.counters.filter(c => c.id !== counterId);
            this.setState({ counters });
        }
        render() { 
            return (<div>
                <button
                    onClick={this.handleReset}
                    className="btn btn-primary btn-sm m-2">Reset</button>
                { this.state.counters.map(counter => 
                    <Counter key={counter.id} onDelete={this.handleDelete} counter={counter}/>
                    )}
            </div>);
        }
    }
    
    class Counter extends Component {
        state = {
            value: this.props.counter.value,
        };
        /* constructor(){
            super();
            this.handleIncrement = this.handleIncrement.bind(this);
        } */
        handleIncrement = (product) => {
            console.log(product);
            this.setState({ value: this.state.value + 1});
        }
        doHandleIncrement = () => {
            this.handleIncrement({ id: 1 });
        }
        render() {
            return (
                <div>
                    <span className={this.getBadgeClasses()}>{this.formatCount()}</span>
                    <button onClick={this.doHandleIncrement} className='btn btn-secondary btn-sm'>Increment</button>
                    <button onClick={() => this.props.onDelete(this.props.counter.id)} className="btn btn-danger btn-sm m-2">Delete</button>
                </div>
            );
        }
        getBadgeClasses() {
            let classes = 'badge m-2 badge-';
            classes += (this.state.value === 0) ? 'warning' : 'primary';
            return classes;
        }
    
        formatCount() {
            const { value } = this.state;
            return value === 0 ? 'Zero' : value;
        }
    }
    

    我们在顶部添加了一个重置按钮,我们试图通过 handleReset 来重置数据,但是回到浏览器中,我们会发现重置功能并没有实现。这是因为我们没有A single source of Truth(真相的唯一来源)。这里我们面对的,是数据唯一性的问题。每个组件,都有自己的state。
    在counter组件中,我们通过 ‘ value: this.props.counter.value ’ 实例化可 state 对象的 value 值,基于它得到的 props 。这行代码只在Counter组件实例创建的时候执行一次,所以当页面加载的时候,我们看到 value 被实例化并可以修改,因为它是本地 state,但是当我们按下重置按钮时,每个 Counter 组件的本地 state 没有更新。


    ff.png

    那么怎么解决这个问题,我们需要删掉在Counter组件中的本地State,然后建立一个唯一的数据源。
    在Counter组件中,我们想删掉Counter组件的State,只保留props来接收组件所需的数据。我们叫这种类型的组件为受控组件。
    受控组件没有自己的state,它所有的数据都来自props,之后再数据需要改变时发起事件。这种控件是完全被其父控件控制的。可解决数据不统一的问题。
    删除 Counter 组件中的 state:

    class Counter extends Component {
        render() {
            return (
                <div>
                    <span className={this.getBadgeClasses()}>{this.formatCount()}</span>
                    <button onClick={() => this.props.onIncrement(this.props.counter)} className='btn btn-secondary btn-sm'>Increment</button>
                    <button onClick={() => this.props.onDelete(this.props.counter.id)} className="btn btn-danger btn-sm m-2">Delete</button>
                </div>
            );
        }
        getBadgeClasses() {
            let classes = 'badge m-2 badge-';
            classes += (this.props.counter.value === 0) ? 'warning' : 'primary';
            return classes;
        }
        formatCount() {
            const { value } = this.props.counter;
            return value === 0 ? 'Zero' : value;
        }
    }
    

    我们完全使用 props对象来呈现数据以及处理数据的修改。我们在 Counters 组件中也需要进行相应的改动:

    class Counters extends Component {
        state = { 
            counters: [
                { id: 1,value: 4 },
                { id: 2,value: 0 },
                { id: 3,value: 0 },
                { id: 4,value: 0 }
            ]
        }
        handleReset = () => {
            const counters = this.state.counters.map(c => {
                c.value = 0;
                return c;
            })
            this.setState({ counters });
        }
        handleIncrement = counter => {
            const counters = [...this.state.counters];
            const index = counters.indexOf(counter);
            counters[index] = {...counter};
            counters[index].value++;
            this.setState({ counters })
        }
        handleDelete = (counterId) => {
            const counters = this.state.counters.filter(c => c.id !== counterId);
            this.setState({ counters });
        }
        render() { 
            return (<div>
                <button
                    onClick={this.handleReset}
                    className="btn btn-primary btn-sm m-2">Reset</button>
                { this.state.counters.map(counter => 
                    <Counter 
                        key={counter.id} 
                        onDelete={this.handleDelete} 
                        onIncrement={this.handleIncrement}
                        counter={counter}/>
                    )}
            </div>);
        }
    }
    

    回到浏览器中,我们发现我们已经实现了增加和重置的功能!

    相关文章

      网友评论

          本文标题:受控组件

          本文链接:https://www.haomeiwen.com/subject/mpmvnqtx.html