非父子通信
状态提升(中间人模式)
pubilc里放的是我们整个项目的静态资源,每次可以通过localhost:3000访问资源也是先访问的public里的index.html
import React, { Component } from 'react';
import axios from 'axios'
import './css/02-communination.css'
class App extends Component {
constructor() {
super()//类的继承
this.state = {
filmList: [],
//转化为状态
info:''
}
axios.get('http://localhost:3000/test.json').then(res => {
console.log(res.data.data.films)
this.setState({
filmList:res.data.data.films
})
})
}
render() {
return (
<div>
{/* {this.state.info} */}
{this.state.filmList.map(item=>
<FilmItem key={item.filmId} {...item} onEvent={(value) => {
//console.log('父组件接收,', value)
this.setState({
info:value
})
}}></FilmItem>)
}
<FilmDetail info={this.state.info}></FilmDetail>
</div>
);
}
}
//受控组件
class FilmItem extends Component {
render() {
// console.log(this.props)
let {name,poster,grade,synopsis}=this.props
return (
<div className='filmitem' onClick={() => {
// console.log(synopsis)
this.props.onEvent(synopsis)
}}>
<img src={poster} alt={name} />
<h4> {this.props.name}</h4>
<div>观众评分{grade}</div>
</div>
);
}
}
class FilmDetail extends Component {
render() {
return (
<div className='filmdetail'>
{this.props.info}
</div>
);
}
}
export default App
效果是这样
发布订阅模式
发布应该晚于订阅,并且发布应该是异步
发布者是触发事件,发送数据的,你要是没有订阅者,发给谁呢?所以订阅者要先进行订阅,这样订阅者才能接收到数据,订阅者就是监听事件接收数据的那个组件
import React, { Component } from 'react';
import axios from 'axios'
import './css/02-communination.css'
let bus = {
//订阅
list:[],
subscribe(callback) {
console.log(callback)
this.list.push(callback)
},
//发布
publish(text) {
//遍历所有的列表,将sub里存入的回调函数们执行
console.log(this.list)
this.list.forEach(callback => {
callback&&callback(text)
})
}
}
class App extends Component {
constructor() {
super()//类的继承
this.state = {
filmList: [],
}
axios.get('http://localhost:3000/test.json').then(res => {
console.log(res.data.data.films)
this.setState({
filmList:res.data.data.films
})
})
}
render() {
return (
<div>
{/* {this.state.info} */}
{this.state.filmList.map(item=>
<FilmItem key={item.filmId} {...item} ></FilmItem>)
}
<FilmDetail ></FilmDetail>
</div>
);
}
}
//受控组件
class FilmItem extends Component {
render() {
// console.log(this.props)
let {name,poster,grade,synopsis}=this.props
return (
<div className='filmitem' onClick={() => {
bus.publish(synopsis)
}}>
<img src={poster} alt={name} />
<h4> {this.props.name}</h4>
<div>观众评分{grade}</div>
</div>
);
}
}
class FilmDetail extends Component {
constructor() {
super()
this.state = {
info:''
}
bus.subscribe((info) => {
console.log('我在filmDetail定义',info)
this.setState({
info:info
})
})
}
render() {
return (
<div className='filmdetail'>
{this.state.info}
</div>
);
}
}
export default App
context方案
const GlobalContext=React.createContext()
使用Provider包住父组件
render() {
return (
<GlobalContext.Provider>
<div>
{/* {this.state.info} */}
{this.state.filmList.map(item=>
<FilmItem key={item.filmId} {...item} ></FilmItem>)
}
<FilmDetail info={this.state.info}></FilmDetail>
</div>
</GlobalContext.Provider>
);
}
Customer包住子组件,里面要放回调函数,记得return出来
因为回调函数会把很关键的参数value传过来,
class FilmItem extends Component {
render() {
// console.log(this.props)
let {name,poster,grade,synopsis}=this.props
return (
<GlobalContext.Consumer>
{
()=>{
return (
<div className='filmitem' onClick={() => {
console.log(synopsis)
}}>
<img src={poster} alt={name} />
<h4> {this.props.name}</h4>
<div>观众评分{grade}</div>
</div>
)
}
}
</GlobalContext.Consumer>
);
}
}
通过context还有状态,修改info:
import React, { Component } from 'react';
import axios from 'axios'
import './css/02-communination.css'
const GlobalContext=React.createContext()
class App extends Component {
constructor() {
super()//类的继承
this.state = {
filmList: [],
info:''
}
axios.get('http://localhost:3000/test.json').then(res => {
console.log(res.data.data.films)
this.setState({
filmList:res.data.data.films
})
})
}
render() {
return (
<GlobalContext.Provider value={{
call: '打电话',
sms: '短信',
info: this.state.info,
changeInfo: (value) => {
this.setState({
info:value
})
}
}}>
<div>
{/* {this.state.info} */}
{this.state.filmList.map(item=>
<FilmItem key={item.filmId} {...item} ></FilmItem>)
}
<FilmDetail info={this.state.info}></FilmDetail>
</div>
</GlobalContext.Provider>
);
}
}
//受控组件
class FilmItem extends Component {
render() {
// console.log(this.props)
let {name,poster,grade,synopsis}=this.props
return (
<GlobalContext.Consumer>
{
(value) => {
console.log(value)
return (
<div className='filmitem' onClick={() => {
console.log(synopsis)
value.changeInfo(synopsis)
}}>
<img src={poster} alt={name} />
<h4> {this.props.name}</h4>
<div>观众评分{grade}</div>
</div>
)
}
}
</GlobalContext.Consumer>
);
}
}
class FilmDetail extends Component {
render() {
return (
<GlobalContext.Consumer>
{ (value)=>{
return <div className='filmdetail'>
detail-{value.info}
</div>
}}
</GlobalContext.Consumer>
);
}
}
export default App
插槽
在App里调用Child组件,在Child组件里再写内容是显示不出来的,会直接把Child组件的内容搬过来
import React, { Component } from 'react';
class Child extends Component {
render() {
return (
<div>
child
/*{'插槽'}*/
</div>
);
}
}
class App extends Component {
render() {
return (
<div>
<Child>
<div>111</div>
</Child>
</div>
);
}
}
export default App;
怎么让他显示?使用插槽,在vue里插槽是起了一个新名字叫slot
在子组件单独使用属性this.props.children在子组件里插入
class Child extends Component {
render() {
return (
<div>
child
{/* 插槽 */}
{
this.props.children//只有这一个写法
}
</div>
);
}
}
children是不会进行对号入座的,如果写了多个插槽的入口,就会把children的内容复制多遍,巨头是以数组的形式存在的:
import React, { Component } from 'react';
class Child extends Component {
render() {
return (
<div>
child
{/* 插槽 */}
{
this.props.children
} {
this.props.children
} {
this.props.children
}
</div>
);
}
}
class App extends Component {
render() {
return (
<div>
<Child>
<div>111</div>
<div>222</div>
<div>333</div>
</Child>
</div>
);
}
}
export default App;
所以如果我们想拆开,可以使用数组的下标来访问:
import React, { Component } from 'react';
class Child extends Component {
render() {
return (
<div>
child
{/* 插槽 */}
{
this.props.children[0]
} {
this.props.children[1]
} {
this.props.children[2]
}
</div>
);
}
}
class App extends Component {
render() {
return (
<div>
<Child>
<div>111</div>
<div>222</div>
<div>333</div>
</Child>
</div>
);
}
}
export default App;
改变数组的顺序可以改变显示的顺序
插槽方便组件的复用,一定程度上减少了父子通信
插槽案例
import React, { Component } from 'react';
class Navbar extends Component{
render() {
return (
<div style={{background:'red'}}>
{this.props.children}
{/* 插槽获取按钮 */}
<span>Navbar</span>
</div>
)
}
}
class Slidebar extends Component{
render() {
return (
<div style={{ background: 'yellow',width:'200px' }}>
<ul>
<li>qq</li>
<li>qq</li>
<li>qq</li>
<li>qq</li>
</ul>
</div>
)
}
}
class App extends Component {
state = {
isShow:false
}
render() {
return (
<div>
<Navbar>
<button>click</button>
</Navbar>
{this.state.isShow&&<Slidebar></Slidebar>}
</div>
);
}
}
export default App;
写轮播图也可以使用插槽,给轮播图的图标和图片内容留个插槽,父组件自由往里塞东西
插槽分为具名查插槽和匿名插槽