2-1、React框架组件化state的使用

本节将开启React框架进阶学习第一篇

点我开始React框架基础学习

大家好,我是Counterrr
不忘初心,砥砺前行

本文目录

一、回顾React框架基础篇中小项目
二、state的使用
三、React框架基础篇小项目的完善

1、回顾React框架基础篇中小项目:

回顾下我们在 1-1 ~ 1-6 React框架基础篇中做了一个小项目,随机选择学习语言小项目,在
1-6、React组件中传值、添加事件和this丢失问题 中我们最后没有真实的去渲染我们手动输入的值,而是在渲染数组里写死的值。那我们这边就开始真实去采用React组件化开发的思想将这个项目完善。

首先我们先回顾下1-4、React中form表单下的input框初使用以及列表渲染在我们还没有进行React组件化重构之前,我们是怎么去改变我们值的时候去重新渲染页面的,我是采用将template模板以及ReactDOM.render( )函数写在了一个函数中,每次去点击修改值的时候,重新去运行了这个函数。

2、state的使用

那state属性在React组件化开发中监听数据的改变,数据的改变就会去重新渲染模板,我们拿AddLang这个组件为例,这个组件是点击添加语言的组件,首先我们先改变MySelectLanApp组件中设置特殊的对象的属性名this.state,代码如下:

class MySelectLanApp extends React.Component {
    constructor (props) {
        super(props)
        this.state = {
            "languages": ['React', 'Vue', 'php']
        }
    }
    render () {
        let obj = {
            "title": "今天学习什么语言?",
            "des": "大家好,我是Counterrr",
            "tips": "不忘初心,砥砺前行",
        }
        return (<div>
            <Header obj={obj}></Header>
            <main>
                <ButtonActive languages={this.state.languages}></ButtonActive>
                <AddLang languages={this.state.languages}></AddLang>
                <Options languages={this.state.languages}></Options>
            </main>
        </div>)
    }
}

我们可以看到在obj对象里的属性都不需要改变,我们就不用写在state对象里,我们可以看到真正需要改变和跟踪是languages数组,我们将它写入state里,然后再给需要用到这个数组的组件中通过props进行传值。页面如下:
在这里插入图片描述
通过state传值页面正常显示。

3、React框架基础篇小项目的完善

接下来我们来修改下MySelectLanApp这个组件。同时也要修改ButtonActive这个组件。也就是选择学习语言按钮和清除按钮,让它拥有能力在点击的时候去操控父组件的state里的值,MySelectLanApp组件代码如下:

class MySelectLanApp extends React.Component {
    constructor (props) {
        super(props)
        this.state = {
            languages: ['react', 'vue', 'php']
        }
        this.removeAllFunc = this.removeAllFunc.bind(this)
        this.selectLanFunc = this.selectLanFunc.bind(this)
    }
    removeAllFunc () {
        this.setState(() => {
            return {
                languages: []
            }
        })
    }
    selectLanFunc () {
        let len = this.state.languages.length;
        let randomNum = Math.floor(Math.random() * len);
        alert(`今天学习的语言是: ${this.state.languages[randomNum]}`);
    }
    render () {
        let obj = {
            "title": "今天学习什么语言?",
            "des": "大家好,我是Counterrr",
            "tips": "不忘初心,砥砺前行",
        }
        return (<div>
            <Header obj={obj}></Header>
            <main>
                <ButtonActive isDisabled={this.state.languages.length == 0} removeAllFunc={this.removeAllFunc} selectLanFunc={this.selectLanFunc}></ButtonActive>
                <AddLang languages={this.state.languages}></AddLang>
                <Options languages={this.state.languages}></Options>
            </main>
        </div>)
    }
}

我们可以看到在MySelectLanApp这个组件上移除了ButtonActive这个组件标签的languages属性,因为这边想要在子组件去修改父组件的state值,只能在父组件上去定义函数,并且通过this.setState( )方法去修改我们state里的值,这个函数接收一个参数类型为函数,这里我们写成了箭头函数的方式,而这个函数又接收一个参数preValue,就是this.state没改变之前的值,这边我们只是在点击的时候将state里的数组置为空所以没有用到就没传。(后面会讲这个参数和异步的情况)。

而这个this.setState( )是一个异步的方法,后面我们再来介绍,也可以写成这种形式来改变this.setState({languages: []})我们一般不建议这种写法,最好给它写成一个函数的方式,这样可以传参,传入之前的值。

我们还可以看到MySelectLanApp这个组件在ButtonActive这个组件标签上新增加了三个属性,我们一个一个来看,第一个属性isDisabled传入这个languages数组的长度是否等于0,如果等于0就说明当前数组为空,那么将传入true,如果不等于0就说明当前数组不为空,将传入false
后面两个属性都是传入一个方法,removeAllFunc里的操作是将state里的languages置为空,而selectLanFunc里的操作是随机弹出languages数组的任意值。

我们在ButtonActive组件上传了3个属性,那么在ButtonActive组件上也要去接收这三个props,好的我们来看看ButtonActive组件的此时的代码:

class ButtonActive extends React.Component {
    constructor (props) {
        super(props)
    }
    render () {
        return (<div>
                <button onClick={this.props.removeAllFunc}>清除</button>
                <button disabled={this.props.isDisabled} onClick={this.props.selectLanFunc}>选择学习的语言</button>
            </div>)
    }
}

好的,我们可以看到ButtonActive组件上,第一个button绑定了removeAllFunc这个函数,那么点击这个的时候,就会去父组件去调用removeAllFunc这个方法,从而移除statelanguages这个数组的所有数据。第二个button绑定了disabled这个属性,那我们知道这个属性是决定按钮是否能点击的一个状态,那我们记得这个isDisabled接收 了truefalse,数组长度为0时为true,那么这个button就不能点击,反之。这个button还绑定了一个selectLanFunc函数,那我们记得这个函数是随机弹出一个选项。好的,我们看看运行效果:
在这里插入图片描述
好的,我们完成了,这次是采用组件化开发的思想去真正的写,而不是像一开始那样全部写在一个模板里,一个jsx语法里。

好的,接下来我们来改造下AddLang这个组件,也就是添加语言的这个组件。我们首先在MySelectLanApp 这个根组件下修改代码,代码如下:

class MySelectLanApp extends React.Component {
    constructor (props) {
        super(props)
        this.state = {
            languages: []
        }
        this.removeAllFunc = this.removeAllFunc.bind(this)
        this.selectLanFunc = this.selectLanFunc.bind(this)
        this.valueHandler = this.valueHandler.bind(this)
    }
    removeAllFunc () {
        this.setState(() => {
            return {
                languages: []
            }
        })
    }
    selectLanFunc () {
        let len = this.state.languages.length;
        let randomNum = Math.floor(Math.random() * len);
        alert(`今天学习的语言是: ${this.state.languages[randomNum]}`);
    }
    valueHandler (value) {
        this.setState((preValue) => {
            return {
                languages: preValue.languages.concat(value)
            }
        })
    }
    render () {
        let obj = {
            "title": "今天学习什么语言?",
            "des": "大家好,我是Counterrr",
            "tips": "不忘初心,砥砺前行",
        }
        return (<div>
            <Header obj={obj}></Header>
            <main>
                <ButtonActive isDisabled={this.state.languages.length == 0} removeAllFunc={this.removeAllFunc} selectLanFunc={this.selectLanFunc}></ButtonActive>
                <AddLang valueHandler={this.valueHandler}></AddLang>
                <Options languages={this.state.languages}></Options>
            </main>
        </div>)
    }
}

可以发现我们新增加了如下代码:

this.valueHandler = this.valueHandler.bind(this)
valueHandler (value) {
        this.setState((preValue) => {
            return {
                languages: preValue.languages.concat(value)
            }
        })
    }

和修改了如下代码:

<AddLang valueHandler={this.valueHandler}></AddLang>

可以知道我们向AddLang这个组件绑定了valueHandler这个属性,并且传入了valueHandler这个函数,那么这个函数有什么作用呢?它接收一个值,并且用到了数组的拼接方法concat去往languages数组中增加接收过来的值。
那么我们看下AddLang这个组件的代码:

class AddLang extends React.Component {
    constructor(props) {
        super(props)
        this.submitFunc = this.submitFunc.bind(this)
    }
    submitFunc (e) {
        e.preventDefault();
        let value = e.target.elements.languages.value;
        if (value == '') {
            alert('请输入!');
        }
        else {
            this.props.valueHandler(value);
            e.target.elements.languages.value = '';
        }
    }
    render () {
        return  (<form onSubmit={this.submitFunc}>
                    <div>
                        <input type="text" name="languages"></input>
                        <button>添加语言</button>
                    </div>
                </form>)
    }
}

可以知道这个组件在触发submitFunc这个方法时,也就是添加语言这个按钮点击时会触发父组件上valueHandler这个方法并且将input中输入的值传给它,也就是在父组件中会将这个值给拼接到languages这个数组上。我们来看看具体运行的结果,如下:
在这里插入图片描述
好的,项目又像一开始那样跑起来,只不过这次我们采用了React中的组件化开发的思想去写的,是不是觉得React中jsx语法写起来非常的漂亮,反正我是这样觉得。
好的给出重构后的整体代码,如下:


class MySelectLanApp extends React.Component {
    constructor (props) {
        super(props)
        this.state = {
            languages: []
        }
        this.removeAllFunc = this.removeAllFunc.bind(this)
        this.selectLanFunc = this.selectLanFunc.bind(this)
        this.valueHandler = this.valueHandler.bind(this)
    }
    removeAllFunc () {
        this.setState(() => {
            return {
                languages: []
            }
        })
    }
    selectLanFunc () {
        let len = this.state.languages.length;
        let randomNum = Math.floor(Math.random() * len);
        alert(`今天学习的语言是: ${this.state.languages[randomNum]}`);
    }
    valueHandler (value) {
        this.setState((preValue) => {
            return {
                languages: preValue.languages.concat(value)
            }
        })
    }
    render () {
        let obj = {
            "title": "今天学习什么语言?",
            "des": "大家好,我是Counterrr",
            "tips": "不忘初心,砥砺前行",
        }
        return (<div>
            <Header obj={obj}></Header>
            <main>
                <ButtonActive isDisabled={this.state.languages.length == 0} removeAllFunc={this.removeAllFunc} selectLanFunc={this.selectLanFunc}></ButtonActive>
                <AddLang valueHandler={this.valueHandler}></AddLang>
                <Options languages={this.state.languages}></Options>
            </main>
        </div>)
    }
}
class Header extends React.Component {
	render () {
		return (<header>
                <div>{this.props.obj.title}</div>
                <div>{this.props.obj.des}</div>
                <div>{this.props.obj.tips}</div>
            </header>)
	}
}
class ButtonActive extends React.Component {
    constructor (props) {
        super(props)
    }
    render () {
        return (<div>
                <button onClick={this.props.removeAllFunc}>清除</button>
                <button disabled={this.props.isDisabled} onClick={this.props.selectLanFunc}>选择学习的语言</button>
            </div>)
    }
}
class AddLang extends React.Component {
    constructor(props) {
        super(props)
        this.submitFunc = this.submitFunc.bind(this)
    }
    submitFunc (e) {
        e.preventDefault();
        let value = e.target.elements.languages.value;
        if (value == '') {
            alert('请输入!');
        }
        else {
            this.props.valueHandler(value);
            e.target.elements.languages.value = '';
        }
    }
    render () {
        return  (<form onSubmit={this.submitFunc}>
                    <div>
                        <input type="text" name="languages"></input>
                        <button>添加语言</button>
                    </div>
                </form>)
    }
}
class Options extends React.Component {
    render () {
        return (<ul>
                <Option languages={this.props.languages}/>
            </ul>)
    }
}
class Option extends React.Component {
    render () {
        return (
            this.props.languages.map((item, index) => {
            return <li key={`option${index}`}>{item}</li>
            })
        )
    }
}

ReactDOM.render(<MySelectLanApp/>, document.getElementById('app'))
发布了31 篇原创文章 · 获赞 27 · 访问量 7953

猜你喜欢

转载自blog.csdn.net/weixin_44103733/article/details/105757052
2-1