React:组件间通信、事件监听理解及ES6 常用新语法
一、组件间通信
方式一: 通过 props 传递
- 共同的数据放在父组件上, 特有的数据放在自己组件内部(state)
- 通过 props 可以传递一般数据和函数数据, 只能一层一层传递
- 一般数据–>父组件传递数据给子组件–>子组件读取数据
- 函数数据–>子组件传递数据给父组件–>子组件调用函数
方式二: 使用消息订阅(subscribe)-发布(publish)机制
- 工具库: PubSubJS
- 下载: npm install pubsub-js --save
- 使用:
import PubSub from ‘pubsub-js’ //引入
PubSub.subscribe(‘delete’, function(data){ }); //订阅
PubSub.publish(‘delete’, data) //发布消息
通过案例来理解使用消息订阅(subscribe)-发布(publish)机制
组件与组件之间的通信案例
注:该案例由于跨域问题还未解决,发送ajax请求时报错,正在解决中。
app.jsx
import React,{Component} from 'react'
import Search from './search'
import Main from './main'
export default class App extends Component{
render (){
return(
<div className="container">
<Search />
<Main />
</div>
)
}
}
main.jsx
import React,{Component} from 'react'
import PropTypes from 'prop-types'
import axios from 'axios'
import PubSub from 'pubsub-js'
export default class Main extends Component{
/*
// 当父组件传属性到子组件中时 先声明属性
static propTypes = {
searchName:PropTypes.string.isRequired
}*/
//main 有四个状态 初始化状态
state = {
initView:true,
loading:false,
users:null,
errorMsg:null,
}
componentDidMount (){
//订阅消息(search)
PubSub.subscribe('search', (msg,searchName) =>{//指定了新的searchName,需要发出请求
console.log(searchName)
//更新状态 (请求中)
this.setState ({
initView:false,
loading:true,
})
//发ajax请求
// const url = 'http://api.githup.com/search/users?q=${searchName}'
const url = "http://api.githup.com/search/users?q="+searchName
// const url = 'http://localhost:53801/api/Project/Query?ProjectName='+searchName
axios.get(url)
.then(response =>{
// 得到响应数据
const result = response.data
console.log(result)
console.log(1)
// const users = sult.items.map(item => ({name:item.})) //item 返回一个对象 所以用小括号
const users = result.items.map(item => {
return {name:item.login,url:item.html_url,avatarUrl:item.avatar_url}
})
// 更新状态(成功)
this.setStata({
loading:false,
users
})
})
.catch(error=>{
//更新状态(失败)
console.log(2)
this.setState({
loading:false,
errorMsg:error.message
})
})
})
}
render (){
const {initView,loading,users,errorMsg}= this.state
const {searchName} = this.props
console.log('render ()',searchName)
if (initView){
return <h2>请输入关键进行搜索:{searchName}</h2>
}else if(loading){
return <h2>正在请求中...</h2>
}else if(errorMsg){
return <h2>{errorMsg}</h2>
}else {
return(
<div className="row">
{
users.map((user,index) =>(
<div className="card" key={index}>
<a href={user.url} >
<img src={user.avatarUrl} style={{width: 100}}/>
</a>
<p className="card-text">user.name</p>
</div>
))
}
</div>
)
}
}
}
search.jsx
import React,{Component} from 'react'
import PropTypes from 'prop-types'
import PubSub from 'pubsub-js'
export default class Search extends Component{
search = () => {
//得到输入的关键字
const searchName = this.input.value.trim()
if(searchName){
//在搜索
//发布消息(search)
PubSub.publish('search',searchName)
}
}
render (){
return(
<section className="jumbotron">
<h3 className="jumbotron-heading">Search Github Users</h3>
<div>
<input type="text" placeholder="enter the name you search" ref={ input => this.input = input}/>
<button onClick={this.search}>Search</button>
</div>
</section>
)
}
}
组件与孙子组件之间的通信案例
删除list下的评论,app.jsx要跨越一个comment-list.jsx组件与comment-item.jsx组件传递消息
app.jsx
import React,{Component} from 'react'
import PropTypes from 'prop-types'
import PubSub from 'pubsub-js'
import './commentItem.css'
export default class CommentItem extends Component{
static propTypes = {
comment:PropTypes.object.isRequired,
index:PropTypes.number.isRequired,
}
handleClick = () =>{
const {comment,index} = this.props
// console.log(deleteComment)
console.log(index)
//提示删除
if(window.confirm("确定删除"+comment.username+"的评论吗?")){
//确定后删除
//发布消息
PubSub.publish('deleteComment',index)
}
}
render (){
const {comment}= this.props
return(
<li className="list-group-item">
<div className="handle">
<a href="javascript:;" onClick={this.handleClick}>删除</a>
</div>
<p className="user"><span >{comment.username}</span><span >说:</span></p>
<p className="centence">{comment.content}</p>
</li>
)
}
}
comment-item.jsx(孙子组件)
import React,{Component} from 'react'
import PropTypes from 'prop-types'
import PubSub from 'pubsub-js'
import './commentItem.css'
export default class CommentItem extends Component{
static propTypes = {
comment:PropTypes.object.isRequired,
index:PropTypes.number.isRequired,
}
handleClick = () =>{
const {comment,index} = this.props
// console.log(deleteComment)
console.log(index)
//提示删除
if(window.confirm("确定删除"+comment.username+"的评论吗?")){
//确定后删除
//发布消息
PubSub.publish('deleteComment',index)
}
}
render (){
const {comment}= this.props
return(
<li className="list-group-item">
<div className="handle">
<a href="javascript:;" onClick={this.handleClick}>删除</a>
</div>
<p className="user"><span >{comment.username}</span><span >说:</span></p>
<p className="centence">{comment.content}</p>
</li>
)
}
}
方式三: redux
(详细讲解网址:)
二、事件监听理解
原生 DOM 事件
- 绑定事件监听
a. 事件名(类型): 只有有限的几个, 不能随便写
b. 回调函数 - 触发事件
a. 用户操作界面
b. 事件名(类型)
c. 数据()
自定义事件(消息机制)
- 绑定事件监听
a. 事件名(类型): 任意
b. 回调函数: 通过形参接收数据, 在函数体处理事件 - 触发事件(编码)
a. 事件名(类型): 与绑定的事件监听的事件名一致
b. 数据: 会自动传递给回调函数
三、ES6 常用新语法
-
定义常量/变量:
const/let
-
解构赋值:
let {a, b} = this.props
、import {aa} from 'xxx'
-
对象的简洁表达: {a, b}
-
箭头函数:
a. 常用场景- 组件的自定义方法: xxx = () => {}
- 参数匿名函数
b. 优点:
- 简洁
- 没有自己的 this,使用引用 this 查找的是外部 this
-
扩展(三点)运算符: 拆解对象(const MyProps = {}, <Xxx {…MyProps}>)
-
类: class/extends/constructor/super
-
ES6 模块化: export default | import