react

什么是虚拟 DOM

虚拟DOM是:用JS来模拟一颗 DOM 树,放在浏览器内存中
当你要改变时,虚拟 DOM 使用 diff 算法进行 新旧虚拟 dom 的比较将修改了的更新到实际的 DOM 树,减少了 DOM 操作

什么是 diff 算法

计算出虚拟 DOM 中真正变化的部分,并且只针对该部分进行 DOM 更新,而非重新渲染整个页面

react 的使用

安装 cnpm i react react-dom -S 安装包

  • react: 专门用于创建组件和虚拟 DOM 的,同时组件的生命周期都在这个包中
  • react-dom: 专门进行 DOM 操作的,最主要的应用场景,就是 ReactDOM.render()
<!DOCTYPE html>
<html lang="zh">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>react基本使用</title>
  </head>
  <body>
    <!-- 创建一个div,虚拟DOM会渲染到这个div里 -->
    <div id="app"></div>
    <!-- 浏览器不支持 import -->
    <script src="../build/build.js"></script>
    <!-- 这里是打包前的代码 -->
    <script>
      import React from "react"; // 创建组件,虚拟 DOM 元素,生命周期
      import ReactDOM from "react-dom"; // 把创建好的虚拟 DOM 放到页面上展示

      // 创建虚拟 DOM
      // 参数 1: 创建元素类型
      // 参数 2: 是一个对象或 null,表示当前这个 DOM 元素的属性
      // 参数 3: 子节点 (文本节点)
      // 参数 4: 其他子节点
      let myh1 = React.createElement(
        "h1",
        { id: "myh1", title: "我是标签" },
        "这是子节点"
      );

      // 把创建好的虚拟 DOM 渲染到页面上
      // 参数 1: 要渲染的那个虚拟 DOM
      // 参数 2: 指定页面上渲染的位置 (类似于Vue中的这个 <div id="app"></div>)
      ReactDOM.render(myh1, document.getElementById("app"));
    </script>
  </body>
</html>

JSX 语法

  • JSX是一种JavaScript的语法扩展(eXtension ),也在很多地方称之为JavaScript XML,因为看起就是一段XML语法;
  • 在 JSX 中的元素添加 class 类名需;要使用 className 来替代 class; htmlFor 替换 label 的 for 属性
  • 正常的 HTML 元素是小写,如果是大写,默认认为是组件
import React from "react";
import ReactDOM from "react-dom";
// 直接运行会报错,要安装 babel 转换成 React.createElement 形式的语法
// 直接写JSXl语法,然后 babel 内部会转成 React.createElement 这种形式
let myh1 = (
  <div id="mydiv" title="aaa">
    这个一个DIV元素
  </div>
);

ReactDOM.render(myh1, document.getElementById("app"));

JSX 中使用变量

  • 通过 {} 语法,Vue 中是{{}}
import React from "react";
import ReactDOM from "react-dom";

let num = 50;
let bool = true;
let title = "可变的title";
let arr = ["钢铁侠", "蜘蛛侠", "雷神", "死特", "美国队长"];
let myh1 = (
  <div id="mydiv" title="aaa">
    {num}
    <hr />

    {bool ? "条件为真" : "条件为假"}
    <hr />

    <p title={title}>{title}</p>
    <hr />
    
    {arr.map((item) => (
      <h3 key={item}>{item}</h3>
    ))}
  </div>
);

// 为啥用 map,map有返回值,会生成一个新数组
ReactDOM.render(myh1, document.getElementById("app"));

react 中使用组件

  • 将页面拆分成一个个小的、可复用的组件。
  • 这样让我们的代码更加方便组织和管理,并且扩展性也更强。
import React from "react";
import ReactDOM from "react-dom";

function Hello() {
  return <div>这是Hello组件</div>;
}

ReactDOM.render(
  <div>
    <Hello></Hello>
  </div>,
  document.getElementById("app")
);

react 组件传参

import React from "react";
import ReactDOM from "react-dom";

function Hello(props) {
  console.log(props);
  return (
    <div>
      这是Hello组件,
      <div>
        这是传过来的数据 ↓<p>名字:{props.send.name}</p>
        <p>ID:{props.send.id}</p>
        <p>颜色:{props.send.color}</p>
      </div>
    </div>
  );
}
let Data = {
  id: 0,
  name: "数据0",
  color: "red",
};
ReactDOM.render(
  <div>
    <Hello send={Data}></Hello>
  </div>,
  document.getElementById("app")
);

子传父

// components 文件夹下的,父组件代码
import React from "react";
import Child from "./Child.jsx"
export default class Father extends React.Component{
  constructor(){
    super()
    this.state = {
      data:"父组件内容"
    }
  }
  render(){
    return (
      <div>
        <h1>父组件---{this.state.data}</h1>
        <Child ParentMethod={ this.FatherClick }></Child>
      </div>
      
    )
  }
  // 父组件方法,传给子组件,子组件通过参数进行修改
  FatherClick = (canshu) =>{
    this.setState({
      data:canshu
    })
  }
}
// components 文件夹下的,子组件代码
import React from "react";
export default class Child extends React.Component{
  render(){
    this.state = {
      Data:"子组件内容"
    } 
    return (
      <div>
        <h1>子组件</h1>
        <button onClick={ ()=> this.ChildClick() }>改变父组件内容</button>
      </div>
    )
  }
  ChildClick(){
    let {Data} = this.state
    this.props.ParentMethod(Data)
  }
}
// 入口文件
import React from "react";
import ReactDOM from "react-dom";
import Father from "./components/Father.jsx"
ReactDOM.render(<Father />, document.getElementById("app"));

兄弟传参

import React from "react";
import ReactDOM from "react-dom";
// 兄弟A组件
class BrotherA extends React.Component {
  constructor() {
    super();
    this.state = {
      data: "传给B组件的参数值",
    };
  }
  render() {
    return (
      <div>
        <h1>兄弟A组件</h1>
        <button onClick={() => this.chuancan()}>按钮A</button>
      </div>
    );
  }
  chuancan = () => {
    let { data } = this.state;
    this.props.change(data);
  };
}
// 兄弟B组件
class BrotherB extends React.Component {
  render() {
    return (
      <div>
        <h1>兄弟B组件</h1>
        A组件的参数:{this.props.CommonData}
      </div>
    );
  }
}

// 共同的父亲
class Father extends React.Component {
  constructor() {
    super();
    this.state = {
      CommonData: "",
    };
  }
  render() {
    return (
      <div>
        <BrotherA change={this.CommonFunction} />
        <BrotherB {...this.state} />
      </div>
    );
  }
  // 跟子传父一样,兄弟A组件把参数给父组件,然后父组件传给兄弟B组件
  CommonFunction = (canshu) => {
    this.setState({
      CommonData: canshu,
    });
  };
}
ReactDOM.render(<Father />, document.getElementById("app"));

将组件抽离为单独的.jsx 文件

// components中的 Hello.jsx文件
import React from "react"; // 你要创建组件必须依赖React包
export default function Hello(props) {
  console.log(props);
  return (
    <div>
      这是Hello组件,
      <div>
        这是传过来的数据 ↓<p>名字:{props.send.name}</p>
        <p>ID:{props.send.id}</p>
        <p>颜色:{props.send.color}</p>
      </div>
    </div>
  );
}
// index.js文件
import React from "react";
import ReactDOM from "react-dom";
import Hello from "./components/Hello.jsx"; // 不能省略后缀名
let Data = {
  id: 0,
  name: "数据0",
  color: "red",
};

ReactDOM.render(
  <div>
    <Hello send={Data}></Hello>
  </div>,
  document.getElementById("app")
);

使用 class 创建组件

  • 注意:使用 class 关键字创建的组件,有自己的私有数据和生命周期函数;
  • 注意:使用 function 创建的组件,只有 props,没有自己的私有数据和生命周期函数和this;
  • 函数组件调用完就会销毁
import React from "react";
import ReactDOM from "react-dom";

class Movie extends React.Component {
  // render函数的作用: 渲染当前组件的 JSX 元素
  constructor() {
    // 子类继承父类则,必须调用 super(),语法规范
    // super()代表父类的构造器(constructor)
    super();
    // 语法规范:在子类中, this 只能放到 super() 之后使用
    this.data = {
      msg: "我是Movie组件的私有数据",
    };
  }
  // 在 class 关键字创建的组件中,如果想使用外界传递过来的 props参数,不需接收,直接通过 this.props .***访问
  render() {
    return (
      <div>
        这是Movie组件---{this.props.send.name}---{this.data.msg}
      </div>
    );
  }
}

let Data = {
  id: 0,
  name: "数据",
  color: "red",
};

ReactDOM.render(<Movie send={Data}></Movie>, document.getElementById("app"));

react 使用行内样式

import React from "react";
import ReactDOM from "react-dom";

function Style() {
  return <div style={{ color: "red", fontSize: "50px" }}>变红</div>;
}

ReactDOM.render(<Style></Style>, document.getElementById("app"));

react 使用样式表

import React from "react";
import ReactDOM from "react-dom";
import css from "./css/index.module.css";

function Style() {
  return <div className={css.test}>样式表样式</div>;
}

ReactDOM.render(<Style></Style>, document.getElementById("app"));

  • css 文件
 /* index.module.css 记得加 module  */
 .test {
  color: rebeccapurple;
  font-size: 50px;
}

react 事件使用

import React from "react";
import ReactDOM from "react-dom";

class My extends React.Component {
  constructor() {
    super();
    // this.state,只能这样写,否则赋值有问题
    this.state = {
      msg:"默认值"
    }
  }
  render() {
    return  <div>
        {/* 三种使用方式 , 最后一种最常用 */}
  		{/* 第一种 */}
        {/* <button onClick = { this.btn.bind(this) }>按钮</button> */}
        { this.state.msg }
        {/* 第三种 */}
        <button onClick = { () => this.btn("哈哈哈") }> 按钮 </button>
       
      </div>
  }
  // 第二种
  btn = (face) => {
     // this.data.msg = "" 这种赋值方式,页面不会更新
     // this.setState 方法的执行,是异步的,如果想拿到更新后的值通过 callback
     // this.setState({ msg:face }, function (){ console.log(this.state.msg) })
    this.setState({ msg:face },function (){ console.log(this.state.msg) })
  }
}
ReactDOM.render(<My></My>, document.getElementById("app"));

setState

  • setState 设计为异步,可以显著的提升性能;
    • 如果每次调用 setState 都进行一次更新,那么意味着 render 函数会被频繁调用,界面重新渲染,这样效率是很低的;
    • 最好的办法应该是获取到多个更新,之后进行批量更新;
  • 如果同步更新了state,但是还没有执行 render 函数,那么 state 和 props 不能保持同步
    • state 和 props 不能保持一致性,会在开发中产生很多的问题;

setState 数据合并

import React from "react";
import ReactDOM from "react-dom";

class Tools extends React.Component {
  constructor() {
    super();
    this.state = {
      content: "Hello world",
      age: 18,
    };
  }
  render() {
    return (
      <div>
        {/* 这里改成了 "哈哈哈哈" 很显然并没有覆盖 age 属性 */}
        {this.state.content}
        <p> {this.state.age}</p>
        <button onClick={(e) => this.change()}> 改变文字 </button>
      </div>
    );
  }
  change() {
    this.setState({
      content: "哈哈哈哈",
    });
    // 因为 React 内部有做一件事
    // Object.assign({},  this.state, { content: "哈哈哈哈" })
    // 所以不用担心会覆盖 age 属性
  }
}
ReactDOM.render(<Tools />, document.getElementById("app"));

const state = { content: "Hello world", age: 18 };
const ChangeState = { content: "哈哈哈哈" };
let result = Object.assign({}, state, ChangeState);
console.log(result);
// { content: '哈哈哈哈', age: 18 }

Ref

import React, { Component, createRef } from "react";
import ReactDOM from "react-dom";
class Ref extends Component {
  constructor() {
    super();
    this.createRef = createRef();
    this.titleEl = "";
  }
  render() {
    return (
      <div>
        {/* 字符串形式 */}
        <h2 ref="titleRef">Hello React</h2>
        {/* 对象形式,推荐 */}
        <h2 ref={this.createRef}>Hello React</h2>
        {/* 函数形式 */}
        <h2 ref={(arg) => (this.titleEl = arg)}>Hello React</h2>

        <button onClick={(e) => this.changeText()}>改变文本</button>
      </div>
    );
  }
  changeText() {
    // 方式一: 不推荐
    this.refs.titleRef.innerHTML = "Hello Coder";
    // 方式二
    this.createRef.current.innerHTML = "Hello JavaScript";
    // 方式三
    this.titleEl.innerHTML = "Hello MySQL";
  }
}
ReactDOM.render(<Ref />, document.getElementById("app"));

Ref获取子组件数据

import React from "react";
import ReactDOM from "react-dom";
class Father extends React.Component {
  componentDidMount(){
    console.log(this.currentDOM.state.data);
  }
  render() {
    return (
      <div>
        <h1>父组件</h1>
        <Child ref={(ChildDOM) => { this.currentDOM = ChildDOM}}></Child>
      </div>
    );
  }
}
class Child extends React.Component {
  constructor(){
    super()
    this.state = {
      data:"子组件数据"
    }
  }
  render() {
    return (
      <div>
        <h1>子组件</h1>
      </div>
    );
  }
}
ReactDOM.render(<Father />, document.getElementById("app"));

react 实现双向数据绑定

import React from "react";
import ReactDOM from "react-dom";
class My extends React.Component {
  constructor() {
    super();
    this.state = {
      msg: "默认值",
    };
  }
  render() {
    return (
      <div>
        {/*

      如果只是把,文本框的 value 属性,绑定到了 state 状态,但是如果不提供 onChange 处理函数的话,
      得到的文本框,将会是一个只读的文本框
      要么提供一个 readOnly (只读文本框),要么提供一个 onChange (监听状态发生改变) 函数

       */}
        {/* (1) <input value={this.state.msg} onChange={(e) => this.textChange(e)} /> */}
        <input value={this.state.msg} onChange={() => this.textChange()} ref="txt" />
        {this.state.msg}
        <button onClick={() => this.btn("哈哈哈")}> 按钮 </button>
      </div>
    );
  }
  textChange = (e) => {
    // 方法 (1) 通过事件对象
    // let newvalue = e.target.value;
    // this.setState({
    //   msg: newvalue,
    // });

    // 方法 (2) 通过 refs
    let newvalue = this.refs.txt.value
    this.setState({
        msg: newvalue,
    });
  };
  btn = (face) => {
    this.setState({ msg: face }, function () {
      console.log(this.state.msg);
    });
  };
}
ReactDOM.render(<My></My>, document.getElementById("app"));

react 生命周期

  • 什么是生命周期,就是组件从创建,运行,到销毁的过程叫做生命周期
    生命周期执行流程
 componentWillMount // 组件将要渲染
 componentDidMount // 组件渲染完成
 componentWillReceiveProps // 组件将要接受 porps 数据
 shouldComponentUpdate(newProps,newState) // 组件收到新的 state 或 porps 判断是否更新,返回布尔值,返回 true 则更新
 componentWillUpdate // 组件将要更新
 componentDidUpdate // 组件更新完成
 componentWillUnMount  // 组件将要卸载

React 性能优化

import React, { PureComponent, memo } from "react";
import ReactDOM from "react-dom";

// Header
// memo 返回一个新的组件
const NewHeader = memo(function Header() {
  console.log("Header被调用");
  return <h2>我是Header组件</h2>;
});

// Main
class Banner extends PureComponent {
  render() {
    console.log("Banner render函数被调用");
    return <h3>我是Banner组件</h3>;
  }
}

function ProductList() {
  console.log("ProductList被调用");
  return (
    <ul>
      <li>商品列表1</li>
      <li>商品列表2</li>
      <li>商品列表3</li>
      <li>商品列表4</li>
      <li>商品列表5</li>
    </ul>
  );
}

class Main extends PureComponent {
  render() {
    console.log("Main render函数被调用");
    return (
      <div>
        <Banner />
        <ProductList />
      </div>
    );
  }
}

// Footer
const Footer = memo(function Footer() {
  console.log("Footer被调用");
  return <h2>我是Footer组件</h2>;
});

export default class App extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      counter: 0,
    };
  }
  render() {
    console.log("App render函数被调用");
    return (
      <div>
        <h2>当前计数: {this.state.counter}</h2>
        <button onClick={(e) => this.increment()}>+1</button>
        <NewHeader />
        <Main />
        <Footer />
      </div>
    );
  }
  increment() {
    this.setState({
      counter: this.state.counter + 1,
    });
  }
}
/* 
当我们更新 APP 组件的值时, Header 这些组件也被调用了 render 函数;
这样是非常浪费性能的,所以把 Component 改成 PureComponent

Component:
  App render函数被调用
  Header被调用
  Main render函数被调用
  Banner render函数被调用
  ProductList被调用
  Footer被调用

PureComponent 的作用:
  PureComponent 会对 props 和 state 做浅层比较,看看有没有改变
  有改变调用 shouldComponentUpdate() { return true  }

shouldComponentUpdate(newPorps,newState) 作用:
  组件收到新的 props 或 state 判断是否更新,返回布尔值,返回 true 则更新

  
PureComponent:
  App render函数被调用
  Header被调用
  Footer被调用

但我们发现 函数组件还是调用了 render 函数,所以我们可以使用 memo
memo 跟 PureComponent 一样也会做浅层比较

PureComponent + memo:
  App render函数被调用
 */
ReactDOM.render(<App />, document.getElementById("app"));

安装 React 脚手架

  • 不要有中文
  1. cnpm install -g create-react-app(安装过这个就直接进行第二步)
  2. create-react-app hellowo(项目名)
  3. cd hellowo
  4. 运行命令 npm start

总结︰脚手架让项目从搭建到开发,再到部署,整个流程变得快速和便捷的工具

react 插条

import React from "react";
import ReactDOM from "react-dom";
// 默认会有一个 constructor
class Movie extends React.Component {
  render() {
    return (
      <div>
         组件插条
        {this.props.children}
        
      </div>
    );
  }
}

ReactDOM.render(
  <Movie>
    <h1>子组件</h1>
    <h1>子组件</h1>
    <h1>子组件</h1>
  </Movie>,
  document.getElementById("app")
);

react 高阶组件

  • 什么是高阶函数:

    • 至少满足以下条件之一:
    • 接受一个或多个函数作为输入
    • 输出一个函数
  • 官方的定义:高阶组件是参数为组件,返回值为新组件的函数

    • 高阶组件本身不是一个组件,而是一个函数
    • 其次,这个函数的参数是一个组件,返回值也是一个组件
import React, { PureComponent } from "react";
import ReactDOM from "react-dom";
/* 


*/
class App extends PureComponent {
  render() {
    return <div>App: {this.props.name}</div>;
  }
}

function FunComponent(Component) {
  class NewComponent extends PureComponent {
    render() {
      return <Component {...this.props} />;
    }
  }
  NewComponent.displayName = "KOKO";
  return NewComponent;
}

/* function FunComponent2(Component) {
   function NewComponent(props) {
    return <Component {...props}/>
  }

  NewComponent.displayName = "KOKO";
  return NewComponent;
} */

const EnhanceComponent = FunComponent(App);

ReactDOM.render(
  <EnhanceComponent name="KOKO" />,
  document.getElementById("app")
);

react 路由

  • 先安装路由,cnpm install react-router-dom -S
  • 使用 react 脚手架,然后把下面代码复制到 App.js
  • to = { {} } 一个 {} 代表变量,两个 { {} } 代表变量里是一个对象
  • 路由模:
    • HashRouter hash模式带#号,页面切换或刷新时,页面不会刷新
    • BrowserRouter browser历史记录模式,没有#号,他是通过历史记录api来进行路由切换的,页面会刷新,木地模式不会
import React from "react";

import "./App.css";

import { BrowserRouter as Router, Link, Route,NavLink } from "react-router-dom";

function Home() {
  return (
    <div>
      <h1>首页</h1>
    </div>
  );
}
function Me(props) {
  console.log(props);
  return (
    <div>
      <h1>个人中心</h1>
    </div>
  );
}
function Goods(props) {
  console.log(props.match.params.id);
  return (
    <div>
      <h1>商品</h1>
    </div>
  );
}

class Routers extends React.Component {
  render() {
    return (
      <div id="app">
        <Router> {/* Router 根,代表这是个路由  */}
          <div className="nav">
            <Link to="/">首页</Link> {/* Link 实现组件跳转,相当于 Vue router-link  */}
            <Link to={{ pathname: "/Me" ,search:"?username=adimin"}}>个人中心</Link> 
            <Link to="/Goods/10086">商品</Link>
			{/* NavLink 可以动态的给选中的导航添加 active 的类名 */}
			<NavLink to="/Goods/10086">商品</NavLink> 
          </div>
	        {/* exact 加上这个只有路由路径唯 / 才显示 Home 组件,不加 exact 只要有 / 就显示 Home 组件 */}
          <Route path="/" exact component={Home}></Route>{/*  Route 路径对应的组件  */}
          <Route path="/Me" component={Me}></Route>
          <Route path="/Goods/:id" component={Goods}></Route>
        </Router>
      </div>
    );
  }
}

export default Routers;

二级路由

import React from "react";

import { BrowserRouter as Router, Link, Route } from "react-router-dom";

function Center(props) {
  console.log(props.location.params); // 跳转参数
  return (
    <div>
      <h1>我的</h1>
      <Link to="/Center/wallet">钱包</Link>
      <Link to="/Center/bill">帐单</Link>
    </div>
  );
}

// 二级路由
function wallet() {
  return <div>钱包</div>;
}
// 二级路由
function bill() {
  return <div>帐单</div>;
}

class Routers extends React.Component {
  render() {
    return (
      <Router>
        <Link to={{ pathname: "/Center", params: { id: 6666666 } }}>我的</Link>
        <Route path="/Center" component={Center}></Route>
        <Route path="/Center/wallet" component={wallet}></Route>
        <Route path="/Center/bill" component={bill}></Route>
      </Router>
    );
  }
}

export default Routers;

Redux

  • 先安装 cnpm install redux -S

  • 解决React数据管理(状态管理),用于中大型,数据比较庞大,组件之间数据交互多的情况下使用

  • 如果你不知道是否需要使用Redux,那么你就不需要用它!

store

  • store:存放数据的仓库,获取仓库 store.getState()
  • 操作仓库 store.dispatch()

action

  • action:命令 Redux 执行规则,必须要包含 type 属性

reducer

  • reducer:执行 action 的命令,把新的 state 发送给 store
// node 中使用 
let redux = require("redux"); // 导入 redux
// React 中使用 
import { createStore } from "redux";

// reducer
const InitState = {
  counter: 0,
};
function reducer(state = InitState, action) {
  switch (action.type) {
    case "ADD":
      return { ...state, counter: state.counter + 1 };
    case "SUB":
      return { ...state, counter: state.counter - action.sum };
  }
}

// store 创建仓库,把数据放到仓库(必须是纯函数)
const Store = redux.createStore(reducer);
// const Store = createStore(reducer);

// action
const action1 = { type: "ADD" };
const action2 = { type: "SUB", sum: 5 };

// 使用 action 它会执行 reducer 函数
Store.dispatch(action1);
Store.dispatch(action2);
console.log(Store.getState().counter);

React-Hook

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
function Btn() {
  /* 
 参数和返回值:
   参数: 初始化值,如果不设置为 undefined
   返回值:数组,包含两个元素
   > 元素一:
      当前状态的值 (第一调用为初始化值)
   > 元素二∶
      设置状态值的函数;
 */
  const [count, setCount] = useState(0); // 初始化值
  const [obj, setObj] = useState({ name: "张三" });
  const [Arr, setArr] = useState(["KOKO", "KOBE", "JANl"]);
  //  useEffect === componentDidMount 和 componentDidUpdate 这两个生命周期
  useEffect(() => {
    console.log("执行了");
    document.title = count;
  }, [count]); // 第二个参数传入一个空数组就只会在第一次时调用;
  // [count] 表示当 count 发生改变了才会调用

  return (
    <div>
      <p>{count}</p>

      <p>
        {obj.name} - {obj.age}
      </p>

      <ul>
        {Arr.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
      
      <button onClick={() => setCount(count + 1)}>数值自增</button>
      
      <button onClick={() => setObj({ name: "李四", age: 15 })}>
        对象按钮
      </button>
      
      <button onClick={() => setArr([...Arr, "TOM"])}>增加列表</button>
    </div>
  );
}
ReactDOM.render(<Btn />, document.getElementById("app"));

useContext

import React, { Component, createContext, useContext } from "react";
import ReactDOM from "react-dom";

let UserContext = createContext();
let SexContext = createContext();

function Grandson() {
  const userContext = useContext(UserContext);
  return (
    <div>
      <div>Grandson组件 👇</div>
      <span>用户昵称: {userContext.name}</span>
      <br />
      <span>年龄: {userContext.age}</span>
    </div>
  );
}

function Son() {
  const sexContext = useContext(SexContext);
  return (
    <div>
      <div>Son组件</div>
      <div>性别: {sexContext.sex}</div>
      <Grandson />
    </div>
  );
}

class APP extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "KOKO",
      age: 20,
    };
  }
  render() {
    return (
      <div>
        <UserContext.Provider value={this.state}>
          <SexContext.Provider value={{ sex: "男" }}>
            <div>APP组件</div>
            <Son />
          </SexContext.Provider>
        </UserContext.Provider>
      </div>
    );
  }
}

ReactDOM.render(<APP />, document.getElementById("app"));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值