受控组件

2019-05-02  本文已影响0人  灯火葳蕤234
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>);
    }
}

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

上一篇下一篇

猜你喜欢

热点阅读