2-1、React框架组件化state的使用
2-2、React函数组件、默认props
大家好,我是Counterrr
不忘初心,砥砺前行
一、箭头函数的简易化
二、React使用state、props完善小项目
三、React生命周期localStorage的使用
好的,为了方便,我们还是以之前写的小项目来做例子,我们知道在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)})
)
}
好的,我们来优化第一项,我们发现当前我们如果输入相同的值则会渲染两次,如下:
这明显不是我们想要的,我们想要在用户输入相同的值的时候,提示用户不能输入相同的值或者不能重复提交,我们将valueHandler
函数改成如下:
valueHandler (value) {
if (!this.state.languages.includes(value)) {
alert('不能重复提交')
}
else {
this.setState((preValue) => ({
languages: preValue.languages.concat(value)}))
}
}
我们在接收到input的值后,利用includes
函数判断这个value
在languages
数组中是否存在,如果存在则弹出不能重复提交,不存在的话则给他拼接上去。效果如下:
好的,我们完成了第一个功能。接着完善下第二个功能,我们需要在每个选项上跟踪一个按钮,来确定删除当前选项,而不是全部清除的场景,那这边我们需要注意,因为我们要去操作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>)
})
)
}
好的我们去运行下我的项目:
好的,我们新增加功能的小项目也跑起来了。
那么我们再来说说当前项目,当写好几个选项后,点击刷新按钮,那么数据将丢失,如果在我们真实的项目中,是不是刷新的话重新向后台去获取数据,或者想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'))