2-3、React使用props以及state、React生命周期localStorage的使用

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

如果还没有学习 1-1 ~ 1-6 React框架基础的话,建议点我开始React框架基础学习

文章系列(React框架进阶)

2-1、React框架组件化state的使用
2-2、React函数组件、默认props

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

本文目录

一、箭头函数的简易化
二、React使用state、props完善小项目
三、React生命周期localStorage的使用

1、箭头函数的简易化:

好的,为了方便,我们还是以之前写的小项目来做例子,我们知道在MySelectLanApp类组件上我们写了:

removeAllFunc () {
        this.setState(() => {
            return {
                languages: []
            }
        })
    }

箭头函数,我们来给它简化下,我们知道箭头函数里面语句就一句,那么可以省略外面花括号,接着还可以省略return关键字,那么写成如下:

removeAllFunc () {
        this.setState(() => { languages: []})
    }

那么我们可以看到这个对象的花括号它这边不会解析成对象,而是会解析成代码块的花括号,那么我们就给这个花括号加上括号,表示它这个是一个表达式,具体写法如下:

removeAllFunc () {
        this.setState(() => ({ languages: []}))
    }

我们再修改valueHandler 函数:

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

2、React使用state、props完善小项目:

好的,我们来优化第一项,我们发现当前我们如果输入相同的值则会渲染两次,如下:
在这里插入图片描述

这明显不是我们想要的,我们想要在用户输入相同的值的时候,提示用户不能输入相同的值或者不能重复提交,我们将valueHandler函数改成如下:

valueHandler (value) {
        if (!this.state.languages.includes(value)) {
            alert('不能重复提交')
        }
        else {
            this.setState((preValue) => ({ languages: preValue.languages.concat(value)}))
        }  
    }

我们在接收到input的值后,利用includes函数判断这个valuelanguages数组中是否存在,如果存在则弹出不能重复提交,不存在的话则给他拼接上去。效果如下:
在这里插入图片描述
好的,我们完成了第一个功能。接着完善下第二个功能,我们需要在每个选项上跟踪一个按钮,来确定删除当前选项,而不是全部清除的场景,那这边我们需要注意,因为我们要去操作languages这个数组,所以我们在MySelectLanApp类组件中,加入函数:

removeCurrentValue (value) {
        this.setState((preValue) => ({
            languages: preValue.languages.filter((item) => {
                return item !== value
            })
        }))
    }

注意我们这边不能直接去改变preValue的值,而是要使用一个不会去改变原数组的方法去写这个去除逻辑。
并且在constructor函数中绑定这个函数的this指向:

this.removeCurrentValue = this.removeCurrentValue.bind(this)

然后我们在Options标签上去传递这个函数:

<Options languages={this.state.languages} removeCurrentValue={this.removeCurrentValue}></Options>

Options函数组件去接收这个函数:

const Options = (props) => {
    return (<ul>
        <Option languages={props.languages} removeCurrentValue={props.removeCurrentValue}/>
    </ul>)
}

并且将这个函数再传递到Option这个标签上,再在Option这个函数组件上去接收这个函数:

const Option = (props) => {
    return (
        props.languages.map((item, index) => {
        return (<div key={`option${index}`}>
                    <li>{item}</li>
                    <button onClick={() => {
                        props.removeCurrentValue(item)
                    }}>删除</button>
                </div>)
        })
    )
}

我们可以看到,我们使用props将函数removeCurrentValue一层一层的传递下来,最后在Option函数组件上去绑定这个移除函数,并且将当前选项值给传递进去,注意我们这边的写法是箭头函数,然后再去触发removeCurrentValue这个函数,那这是为什么呢?为什么不直接写成:

<button onClick={props.removeCurrentValue(item)}>删除</button>

那如果直接写成这样的话函数没有返回值,则会接收一个undefined,那么点击删除按钮将什么都不发生。
所以我们要写成这样形式:

const Option = (props) => {
    return (
        props.languages.map((item, index) => {
        return (<div key={`option${index}`}>
                    <li>{item}</li>
                    <button onClick={() => {
                        props.removeCurrentValue(item)
                    }}>删除</button>
                </div>)
        })
    )
}

好的我们去运行下我的项目:
在这里插入图片描述
好的,我们新增加功能的小项目也跑起来了。

3、React生命周期localStorage的使用:

那么我们再来说说当前项目,当写好几个选项后,点击刷新按钮,那么数据将丢失,如果在我们真实的项目中,是不是刷新的话重新向后台去获取数据,或者想localStorage里去取数据,那么我们这边没有后台,就先讲讲localStorage的用法吧。
那么我们先来了解下React的生命周期几个常用的钩子函数,当然这些钩子函数只有在类组件中才可以使用。
第一个钩子函数componentDidMount,这个钩子函数在组件一开始就会调用。
第二个钩子函数componentDidUpdate,这个钩子函数在数据发生改变时就会触发。钩子函数componentDidUpdate接收两个参数,第一个参数是上一次的props,第二个参数是上一次的state
具体react的生命周期,可以查看这里
那如何利用这两个钩子函数和我们的localStorage的结合使用呢?我们在MySelectLanApp类组件中写入这两个钩子函数
代码如下:

componentDidMount () {
        this.setState(() => ({
            languages: JSON.parse(localStorage.getItem('languages')) || []
        }))
    }
componentDidUpdate(preProps, preState) {
        if (this.state.languages.length !== preState.languages.length) {
            localStorage.setItem('languages', JSON.stringify(this.state.languages))
        }
    }

通过代码我们可以知道在每次用户刷新界面时,都去localStorage去取这个数组,如果没有就设置为空数组。在数据发生改变时,并且这次数组的长度和上一次数组的长度不相等时,我们去设置这个localStorage。好的我们再次去运行这个小项目,效果如下:
在这里插入图片描述
好的,此时刷新也能够将我们之前输入的值给渲染出来了。
我们通过这个小项目,一点一点去完善它,可以学习到挺多关于react的知识,更快的去了解了react的语法和一些使用技巧。

最后给出这节课修改后的代码:

class MySelectLanApp extends React.Component {
    constructor (props) {
        super(props)
        this.state = {
            languages: props.languages
        }
        this.removeAllFunc = this.removeAllFunc.bind(this)
        this.selectLanFunc = this.selectLanFunc.bind(this)
        this.valueHandler = this.valueHandler.bind(this)
        this.removeCurrentValue = this.removeCurrentValue.bind(this)
    }
    removeAllFunc () {
        this.setState(() => ({languages: []}))
    }
    selectLanFunc () {
        let len = this.state.languages.length;
        let randomNum = Math.floor(Math.random() * len);
        alert(`今天学习的语言是: ${this.state.languages[randomNum]}`);
    }
    valueHandler (value) {
        if (this.state.languages.includes(value)) {
            alert('不能重复提交')
        }
        else {
            this.setState((preValue) => ({ languages: preValue.languages.concat(value)}))
        }  
    }
    removeCurrentValue (value) {
        this.setState((preValue) => ({
            languages: preValue.languages.filter((item) => {
                return item !== value
            })
        }))
    }
    componentDidMount () {
        this.setState(() => ({
            languages: JSON.parse(localStorage.getItem('languages')) || []
        }))
    }
    componentDidUpdate(preProps, preState) {
        if (this.state.languages.length !== preState.languages.length) {
            localStorage.setItem('languages', JSON.stringify(this.state.languages))
        }
    }
    render () {
        return (<div>
            <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} removeCurrentValue={this.removeCurrentValue}></Options>
            </main>
        </div>)
    }
}
MySelectLanApp.defaultProps = {
    languages: []
}
const Header = (props) => {
    return (<header>
                <div>{props.obj.title}</div>
                <div>{props.obj.des}</div>
                <div>{props.obj.tips}</div>
            </header>    
        )
}
Header.defaultProps = {
    obj: {
        title: '今天学习了吗?',
        des: '大家好,我爱撸码。',
        tips: '如果学不死就往死里学。'
    }
}
const ButtonActive = (props) => {
    return (<div>
                <button onClick={props.removeAllFunc}>清除</button>
                <button disabled={props.isDisabled} onClick={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>)
    }
}
const Options = (props) => {
    return (<ul>
        <Option languages={props.languages} removeCurrentValue={props.removeCurrentValue}/>
    </ul>)
}
const Option = (props) => {
    return (
        props.languages.map((item, index) => {
        return (<div key={`option${index}`}>
                    <li>{item}</li>
                    <button onClick={() => {
                        props.removeCurrentValue(item)
                    }}>删除</button>
                </div>)
        })
    )
}

ReactDOM.render(<MySelectLanApp/>, document.getElementById('app'))
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你华还是你华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值