本节将开启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
这个方法,从而移除state
里languages
这个数组的所有数据。第二个button
绑定了disabled
这个属性,那我们知道这个属性是决定按钮是否能点击的一个状态,那我们记得这个isDisabled
接收 了true
和false
,数组长度为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'))