滴水能把石穿透,万事功到天然成——zZ先森react
话很少说,直接上干货!bash
父组件调用子组件,经过属性传递props,属于单向数据传递,即只能是父组件向子组件传递属性,反过来不能够。ide
父组件经过属性的方式把能操做本身状态的方法传递给子组件,而后子组件拿到方法进行操做,经过方法修改相应的信息。底层仍是基于属性传递函数
JSONP和JSBridge的运行机制和回调函数方式相似ui
$on
和$emit
实现的信息通讯手动实现一个发布订阅:this
class EventEmit{
//事件池 {事件名:[订阅方法...]}
pond = {};
$on(eventName,func){
if(!this.pond.hasOwnProperty(eventName)){
//每个事件名对应一系列的方法
this.pond.eventName = [];
}
//订阅方法的去重
this.pond[eventName].some(item=>item===func) return;
this.pond[eventName].push(func)
}
$emit(eventName,...rargs){
let funArr = this.pond[eventName]||[];
funcArr.forEach(item=>{
item.bind(null,...args)
})
}
export default new EventEmit();
}
复制代码
import React from "react";
import EM from "./EventEmit";
class Main tetends React.component{
state = {
supNum:0,
oppNum:0
}
handle=(type)=>{
let {subNum,oppNum} = this.state;
if(type==="sup"){
this.setState({
subNum:subNum++;
})
}else{
this.setState({
this.setState({
oppNum:oppNum++;
})
})
}
}
render(){
let {oppNum,oppNum} = this.state;
return <main className="mainBox">
<p>支持人数{supNum}</p>
<p>反对人数{oppNum}</p>
</main>
}
componentDidMount(){
EM.$on("mainHandle",handle)
}
}
class Footer extends React.component{
render(){
return <footer className="footerBox">
<button onClick = {ev=>{
EM.$emit("mainHandle","SUP");
EM.$emit("totalHandle")
}}>支持</button>
<button onClick = {ev=>{
EM.$emit("mainHandle","OPP")
EM.$emit("totalHandle")
}}>反对</button>
</footer>
}
}
export default class Vote extends React.component{
state = {total:0}
return {
<div className="voteBox">
<header className="headerBox">
<h3>{this.props.title}</h3>
<span>投票人数:{this.state.total}</span>
</header>
<Main></Main>
<Footer></Footer>
<div>
}
componentDidMount(){
EM.$on("totalHandle",()=>{
this.setState({
total:this.state.tota+1
})
})
}
}
复制代码
把后代须要用到的属性和方法,放到祖先元素的上下文中,后代组件能够直接注册获取使用。【适用于有一个共同祖先组件】spa
React.createContext()
;// 建立一个上下文对象(REACT中的 CONTEXT API【最新】)
import React from 'react';
const ThemeContext = React.createContext();
export default ThemeContext;
复制代码
ThemeContext.Provider value={...}
return{
<ThemeContext.Provider
value=({
//须要提供的上下文信息
...state
})>
</ThemeContext.Provider>
}
复制代码
技巧: 须要用到的上下文,咱们通常设置为祖先元素的状态,这样后期只要修改状态,触发getInitialState 钩子函数执行并从新渲染, 这样就会从新设置上下文中的信息,后代组件也从新渲染,并拿到最新的信息。3d
context=React.useContext(ThemeContext)
//经过HOOKS函数 解构出上下文中所需的方法或属性
const { handle } = useContext(ThemeContext);
复制代码
static childContextTypes = {...}
getChildContext(){return{...}}
【也属于生命周期函数】static contextTypes = {...}
【声明状态类型必须和祖先组件提供的类型一致】import React from 'react';
import PropTypes from 'prop-types';
class Main extends React.Component {
// 获取的上下文信息挂载到实例的this.context中了(获取的上下文信息是能够修改的,
可是并无影响到祖先)
static contextTypes = {
supNum: PropTypes.number,
oppNum: PropTypes.number
};
/*constructor(props, context) {
super(props, context);
} */
render() {
return <main className="mainBox">
<p>支持人数:{this.context.supNum}</p>
<p>反对人数:{this.context.oppNum}</p>
</main>;
}
}
class Footer extends React.Component {
static contextTypes = {
handle: PropTypes.func
};
render() {
return <footer className="footerBox">
<button onClick={ev => {
this.context.handle('SUP');
}}>支持</button>
<button onClick={ev => {
this.context.handle('OPP');
}}>反对</button>
</footer>;
}
}
export default class Vote extends React.Component {
static childContextTypes = {
supNum: PropTypes.number,
oppNum: PropTypes.number,
handle: PropTypes.func
};
getChildContext() {
//=>第一次在getIntialState以后执行,每当祖先组件中的状态改变,
从新渲染的时候,此钩子函数也会从新被执行
return {
supNum: this.state.supNum,
oppNum: this.state.oppNum,
handle: this.handle
}
}
state = {
supNum: 0,
oppNum: 0
};
handle = type => {
let { supNum, oppNum } = this.state;
type === 'SUP' ? this.setState({ supNum: supNum + 1 }) : this.setState({ oppNum: oppNum + 1 });
};
render() {
return <div className="voteBox">
<header className="headerBox">
<h3>{this.props.title}</h3>
<span>N:{this.state.supNum + this.state.oppNum}</span>
</header>
<Main></Main>
<Footer></Footer>
</div>;
}
}
复制代码
ThemeContext.Provider
中的value注册上下文信息import React from 'react';
import VoteMain from './VoteMain';
import VoteFooter from './VoteFooter';
import ThemeContext from './ThemeContext';
export default class Vote extends React.Component {
state = {
supNum: 0,
oppNum: 0
};
render() {
let { supNum, oppNum } = this.state;
/* 基于ThemeContext.Provider中的value注册上下文信息 */
return <ThemeContext.Provider
value={{
supNum,
oppNum,
handle: this.handle
}}>
<div className="voteBox">
<header className="voteHeader">
<h3>{this.props.title}</h3>
<span>【{supNum + oppNum}】</span>
</header>
<VoteMain></VoteMain>
<VoteFooter></VoteFooter>
</div>
</ThemeContext.Provider>;
}
handle = (lx = 0) => {
// 支持
if (lx === 0) {
this.setState({ supNum: this.state.supNum + 1 });
return;
}
// 反对
this.setState({ oppNum: this.state.oppNum + 1 });
}
};
复制代码
import React from 'react';
import ThemeContext from './ThemeContext';
export default class voteMain extends React.Component {
render() {
return <ThemeContext.Consumer>
{context => {
let { supNum, oppNum } = context;
return <main className="voteMain">
<p>支持数:{supNum}</p>
<p>反对数:{oppNum}</p>
<p>支持率:{this.ratio(supNum, oppNum)}</p>
</main>;
}}
</ThemeContext.Consumer>;
}
ratio = (supNum, oppNum) => {
let total = supNum + oppNum;
if (total === 0) return '--';
return (supNum / total * 100).toFixed(2) + '%';
}
}
复制代码
this.context
import React from 'react';
import ThemeContext from './ThemeContext';
export default class voteFooter extends React.Component {
static contextType = ThemeContext;
render() {
return <footer className="voteFooter">
<button onClick={_ => {
this.context.handle(0);
}}>支持</button>
<button onClick={_ => {
this.context.handle(1);
}}>反对</button>
</footer>;
}
};
复制代码
在项目中最经常使用的是基于属性传递PROPS,和执行上下文进行传递,因为在祖先组件放置上下文,显得有点臃肿,因此最最经常使用的是基于公共状态管理Redux。后续持续总结更新!code