React16 基础
- 阐述
- 新建服务菜单组件
- 父组件向子组件传值
- 子组件向父组件传递数据
- warning警告
- 获取数组索引下标
- 子组件调用父组件方法
- 预览最终效果
- index.js
- Xiaojiejie.js(未用)
- BeautyItem.js
- Beauty.js
阐述
现在的服务菜单已经完美的制作好了,但是这从头到尾我们只用了一个组件,但是在实际工作中肯定是团队开发,我们会把一个大功能分成不同的组件。
比如把文本框和按钮单独一个组件,把下面的服务列表单独一个组件,这涉及了一个组件拆分的能力和知识。
本文就把服务菜单进行一个拆分。
新建服务菜单组件
在 src
目录下,新建一个文件,这里就叫做 BeautyItem.js
,然后先把最基础的结构写好(这里最好练习一下上节课学习的快捷键)。
import React, { Component } from 'react'; //imrc
class BeautyItem extends Component { //cc
render() {
return (
<li>美女</li>
);
}
}
export default BeautyItem;
写好这些代码后,就可以到以前写的 Xiaojiejie.js
文件中用 import
进行引入,
代码如下:
import BeautyItem from "./BeautyItem";
### 修改 Beauty 组件
已经引入了新写的组件,这时候原来的代码要如何修改才能把新组件加入?
把原来的代码注释掉,当然你也可以删除掉,我这里就注释掉了,注释方法如下:
{/*
<li
key={index+item}
onClick={this.deleteItem.bind(this,index)}
dangerouslySetInnerHTML={{__html:item}}
>
</li>
*/ }
然后在最外层加入包裹元素 <div>
,为的是防止两个以上的标签,产生错误信息。
最后直接写入 Beauty
标签就可以了。
<BeautyItem />
已经把 ”美女”
组件做了一个基本的拆分,但是还不能实现随着输入,显示出输入的内容。
这里涉及的是父组件向子组件传值。
然后点击删除,就相当于子组件向父组件传值。
父组件向子组件传值
这里只介绍最实用的,最快速的上手方法。
就是使用组件属性的形式父组件给子组件传值。
比如:
我们在 <BeautyItem>
组件中加入 content
属性,然后给属性传递 {item}
,这样就完成了父组件向子组件传值。
<BeautyItem content={item} />
现在值已经顺利的传递了过去,这时候可以通过 this.props.xxx
的形式进行接受,比如传递过来的值,可以用如下代码进行接收。
import React, { Component } from 'react'; //imrc
class BeautyItem extends Component { //cc
render() {
return (
<div>{this.props.content}</div>
);
}
}
export default BeautyItem;
修改完美女子项的组件后,可以打开浏览器进行预览了。
试着添加几个新的选项试一下,比如美女踩背。
玩笑归玩笑,学到这里你要记住一点:
父组件向子组件传递内容,靠属性的形式传递。
子组件向父组件传递数据
现在要作这样一个功能:
点击组件中的菜单项后,删除该菜单项。
在前边的教程中已经学习了这个知识,只是现在组件拆分了,就涉及了一个子组件向父组件传递数据的知识需要掌握。
先来绑定点击事件,这时候当然是要在 BeautyItem
组件中绑定了。
代码如下:
import React, { Component } from 'react'; //imrc
class BeautyItem extends Component { //cc
render() {
return (
<div onClick={this.handleClick}>{this.props.content}</div>
);
}
handleClick(){
console.log('撩拨了小姐姐')
}
}
export default BeautyItem;
warning警告
这时候进行预览,打开F12,再点击服务菜单项,就会再console里显示出 ”撩拨了小姐姐”
的字样。但是console里还有一个warning警告,这个警告我们见过,就是要求循环时必须设置key
值。
修改 Beauty
组件的 render
代码如下:
<ul>
{
this.state.list.map((item,index)=>{
return (
<BeautyItem
key={index+item}
content={item} />
)
})
}
</ul>
绑定成功后,现在就要通过操作子组件删除父组件里的数据了。
但是React有明确规定,子组件时不能操作父组件里的数据的,所以需要借助一个父组件的方法,来修改父组件的内容。
其实在以前已经写了一个删除方法 deleteItem
,现在要作的就是子组件调用这个方法。
//删除单项服务
deleteItem(index){
let list = this.state.list
list.splice(index,1)
this.setState({
list:list
})
}
获取数组索引下标
那现在问题来了,要删除就要知道索引值,还是需要通过父组件传递给子组件。
这里还是通过 props
属性的形式进行传递。
<ul>
{
this.state.list.map((item,index)=>{
return (
<BeautyItem
key={index+item}
content={item}
index={index} />
)
})
}
</ul>
然后修改 BeautyItem
组件,在 handleClick
方法里,写入下面代码:
handleClick(){
console.log(this.props.index)
}
这时候预览一下,你会发现点击列表执行删除方法后报错,错误还是我们的老朋友没有 bind(this)
。
那可以用以前的老方法绑定 this
。
return (
<div onClick={this.handleClick.bind(this)}>
{this.props.content}
</div>
);
这样是可以解决的,但是肯定会有小伙伴说,我看别人不是这样写的,而是在构造函数里绑定的。(有言曰:构造函数中绑定性能会高一些,特别是在高级组件开发中,会有很大的作用)
constructor
绑定 this
方法。
import React, { Component } from 'react'; //imrc
class BeautyItem extends Component { //cc
//--------------主要代码--------start
constructor(props){
super(props)
this.handleClick=this.handleClick.bind(this)
}
//--------------主要代码--------end
render() {
return (
<div onClick={this.handleClick}>
{this.props.content}
</div>
);
}
handleClick(){
console.log(this.props.index)
}
}
export default BeautyItem;
子组件调用父组件方法
如果子组件要调用父组件方法,其实和传递数据差不多,只要在组件调用时,把方法传递给子组件就可以了,记得这里也要进行 this
的绑定,如果不绑定子组件是没办法找到这个父组件的方法的。
<ul>
{
this.state.list.map((item,index)=>{
return (
<BeautyItem
key={index+item}
content={item}
index={index}
//关键代码-------------------start
deleteItem={this.deleteItem.bind(this)}
//关键代码-------------------end
/>
)
})
}
</ul>
传递后,在 BeautyItem
组件里直接用就可以了,代码如下:
handleClick(){
this.props.deleteItem(this.props.index)
}
到此为止,就算是实现了子组件向父组件传值。
特别提醒:
本文内容是React体系中非常重要的一节,小伙伴们可以多看几遍,并进行练习。因为真正的React开发工作,每天写的就是各种组件,传值是组件之间产生联系的必要一环,无法跳跃。所以一定要学好。
预览最终效果
index.js
Xiaojiejie.js(未用)
这个没用上
BeautyItem.js
子组件
import React, { Component } from 'react'; //imrc
class BeautyItem extends Component { //cc
//--------------主要代码--------start
constructor(props){
super(props)
this.handleClick=this.handleClick.bind(this)
}
//--------------主要代码--------end
render() {
return (
<div onClick={this.handleClick} dangerouslySetInnerHTML={{__html:this.props.content}}>
</div>
);
}
handleClick(){
console.log(this.props.index)
this.props.deleteItem(this.props.index)
}
}
export default BeautyItem;
Beauty.js
父组件
import React,{Component,Fragment } from 'react'
import BeautyItem from './BeautyItem'
class Beauty extends Component{
//js的构造函数,由于其他任何函数执行
constructor(props){
super(props) //调用父类的构造函数,固定写法
this.state={
inputValue:'' , // input中的值
list: //服务列表
}
}
render(){
return (
<Fragment>
{/* 正确注释的写法 */}
<div>
<label htmlFor="willem">加入服务:</label>
<input id="willem" className="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
<button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>
<ul>
{
this.state.list.map((item,index)=>{
return (
<BeautyItem
key={index+item}
content={item}
index={index}
//关键代码-------------------start
deleteItem={this.deleteItem.bind(this)}
//关键代码-------------------end
/>
)
})
}
</ul>
</Fragment>
)
}
inputChange(e){
// console.log(e.target.value);
// this.state.inputValue=e.target.value;
this.setState({
inputValue:e.target.value
})
}
//增加服务的按钮响应方法
addList(){
this.setState({
list:[...this.state.list,this.state.inputValue],
inputValue:''
})
}
//删除单项服务
deleteItem(index){
let list = this.state.list
list.splice(index,1)
this.setState({
list:list
})
}
}
export default Beauty