react【三】受控组件/高阶组件/portals/fragment/严格模式/动画

1、受控组件

1.1 认识受控组件

在这里插入图片描述

import React, {
    PureComponent } from "react";

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

    this.state = {
   
      userName: "",
    };
  }

  inputChange(e) {
   
    const value = e.target.value;
    this.setState({
    userName: value });
  }

  submitChange(e) {
   
    // 1.阻止表单的默认事件 表单默认会被刷新
    e.preventDefault();

    // 2.在这里修改表单数据
    console.log(e);

    // 3.发送网络请求
  }

  render() {
   
    const {
    userName } = this.state;

    return (
      <div>
        <form onSubmit={
   (e) => this.submitChange(e)}>
          <label htmlFor="userName">
            用户:
            <input
              id="userName"
              type="text"
              name="userName"
              value={
   userName}
              onChange={
   (e) => this.inputChange(e)}
            ></input>
          </label>
          <button type="submit">注册</button>
        </form>
      </div>
    );
  }
}

export default App;

在这里插入图片描述

1.2 checkout

在这里插入图片描述

import React, {
    PureComponent } from "react";

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

    this.state = {
   
      userName: "",
      password: "",
      isAgree: false,
      hobbies: [
        {
    value: "sing", text: "唱", isChecked: false },
        {
    value: "dance", text: "跳", isChecked: false },
        {
    value: "rap", text: "rap", isChecked: false },
      ],
    };
  }

  handleAgreeChange(e) {
   
    this.setState({
    isAgree: e.target.checked });
  }

  handleHobbiesChange(e, index) {
   
    const hobbies = [...this.state.hobbies];
    hobbies[index].isChecked = e.target.checked;

    this.setState({
    hobbies });
  }

  submitChange(e) {
   
    // 1.阻止表单的默认事件 表单默认会被刷新
    e.preventDefault();

    // 2.在这里修改表单数据
    console.log(e);
    const hobbies = this.state.hobbies.filter((item) => item.isChecked);
    console.log(hobbies);

    // 3.发送网络请求
  }

  render() {
   
    const {
    isAgree, hobbies } = this.state;

    return (
      <div>
        <form onSubmit={
   (e) => this.submitChange(e)}>
          {
   /* 单选 */}
          <label htmlFor="agree">
            <input
              type="checkbox"
              id="agree"
              checked={
   isAgree}
              onChange={
   (e) => this.handleAgreeChange(e)}
            />
            单选
          </label>

          {
   /* 多选 */}
          <div>
            {
   hobbies.map((item, index) => {
   
              return (
                <label htmlFor={
   item.value} key={
   index}>
                  <input
                    type="checkbox"
                    id={
   item.value}
                    checked={
   item.isChecked}
                    onChange={
   (e) => this.handleHobbiesChange(e, index)}
                  />
                  {
   item.text}
                </label>
              );
            })}
          </div>

          <button type="submit">注册</button>
        </form>
      </div>
    );
  }
}

export default App;

1.3 selected

在这里插入图片描述

import React, {
    PureComponent } from "react";

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

    this.state = {
   
      fruit: "orange",
      fruits: ["orange", "apple"],
    };
  }

  submitChange(e) {
   
    // 1.阻止表单的默认事件 表单默认会被刷新
    e.preventDefault();

    // 2.在这里修改表单数据
    console.log(e);

    // 3.发送网络请求
  }

  // 单选
  fruitChange(e) {
   
    console.log(e.target.value);
    this.setState({
    fruit: e.target.value });
  }

  //  多选
  fruitsChange(event) {
   
    // event.target.selectedOptions 获取到的不是数组 HTMLCollection [option]
    // 方法1
    // const options = Array.from(event.target.selectedOptions);
    // const values = options.map((item) => item.value);
    // this.setState({ fruits: values });

    // 额外补充: Array.from(可迭代对象)
    // Array.from(arguments,()=>{})

    // 方法2
    const values = Array.from(
      event.target.selectedOptions,
      (item) => item.value
    );

    this.setState({
    fruits: values });
  }

  render() {
   
    const {
    fruit, fruits } = this.state;

    return (
      <div>
        <form onSubmit={
   (e) => this.submitChange(e)}>
          {
   /* select单选 */}
          <select value={
   fruit} onChange={
   (e) => this.fruitChange(e)}>
            <option value="apple">苹果</option>
            <option value="orange">橘子</option>
            <option value="banana">香蕉</option>
          </select>

          {
   /* select多选 */}
          <select
            value={
   fruits}
            multiple
            onChange={
   (e) => this.fruitsChange(e)}
          >
            <option value="apple">苹果</option>
            <option value="orange">橘子</option>
            <option value="banana">香蕉</option>
          </select>

          <button type="submit">注册</button>
        </form>
      </div>
    );
  }
}

export default App;

1.4 非受控组件

在这里插入图片描述

import React, {
    PureComponent, createRef } from "react";

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

    this.state = {
    intro: "kiki" };
    this.introRef = createRef();
  }

  submitChange(e) {
   
    // 1.阻止表单的默认事件 表单默认会被刷新
    e.preventDefault();

    // 2.在这里修改表单数据
    console.log(e);
    console.log(this.introRef.current.value);

    // 3.发送网络请求
  }

  render() {
   
    const {
    intro } = this.state;

    return (
      <div>
        <form onSubmit={
   (e) => this.submitChange(e)}>
          <input type="text" defaultValue={
   intro} ref={
   this.introRef}></input>

          <button type="submit">注册</button>
        </form>
      </div>
    );
  }
}

export default App;

2、高阶组件

2.1 认识高阶组件

在这里插入图片描述在这里插入图片描述

import React, {
    PureComponent } from "react";

// 普通类组件
class HelloWorld extends PureComponent {
   
  constructor(props) {
   
    super(props);
  }
  render() {
   
    const {
    name } = this.props;
    return (
      <div>
        <span>普通的类组件-{
   name}</span>
      </div>
    );
  }
}

// 高阶组件
const Hoc = (Comp) => {
   
  class NewCpn extends PureComponent {
   
    render() {
   
      return (
        <div>
          <h1>我是高阶组件</h1>
          {
   /* 高阶组件传递参数给子组件 */}
          <Comp name="kiki" />
        </div>
      );
    }
  }
  return NewCpn;
};

// 调用高阶组件
const HelloWorldHOC = Hoc(HelloWorld);

class componentName extends PureComponent {
   
  render() {
   
    return (
      <div>
        {
   /* 对高阶组件的使用 */}
        <HelloWorldHOC />
      </div>
    );
  }
}

export default componentName;

2.2 应用1-props增强的基本使用

在这里插入图片描述

  • enhanced_props.js
import React, {
    PureComponent } from "react";

const enhancedUserInfo = (OriginComponent) => {
   
  class NewComponent extends PureComponent {
   
    constructor(props) {
   
      super(props);

      this.state = {
   
        userInfo: {
   
          name: "kiki",
          age: "18",
        },
      };
    }
    render() {
   
      // 1.将state.userInfo的内容全部传递给子组件
      // 2.将OriginComponents 原本的props也给注入
      return <OriginComponent {
   ...this.props} {
   ...this.state.userInfo} />;
    }
  }
  return NewComponent;
};

export default enhancedUserInfo;

  • about.jsx
import React, {
    PureComponent } from 'react'
import enhancedUserInfo from '../hoc/enhanced_props'

export class About extends PureComponent {
   
  render() {
   
    return (
      <div>About: {
   this.props.name}</div>
    )
  }
}

export default enhancedUserInfo(About)

  • App.jsx
import React, {
    PureComponent } from "react";
import enhancedUserInfo from "./hoc/enhanced_props";
import About from "./pages/About";

const Home = enhancedUserInfo((props) => {
   
  // 通过enhancedUserInfo 将它本身的state传递给该函数组件
  return (
    <h1>
      {
   props.name}-{
   props.age}
    </h1>
  );
});

const HelloWord = enhancedUserInfo((props) => {
   
  return (
    <h1>
      {
   /* 调用组件的时候传递的参数也可以拿到 */}
      {
   props.name}-{
   props.age}-{
   props.banner}
    </h1>
  );
});

export class App extends PureComponent {
   
  render() {
   
    return (
      <div>
        <Home />
        {
   /* 给高阶函数传递props */}
        <HelloWord banner="['a','b']" />
        {
   /* 调用已经注入enhancedUserInfo的组件 */}
        <About />
      </div>
    );
  }
}

export default App;

2.3 对象增强的应用场景-context共享

  • 使用高阶组件来跨组件传参
    在这里插入图片描述

  • theme_context.js (创建context)

import {
    createContext } from "react";

const themeContext = createContext();

export default themeContext;

  • with_theme.js(props增强
import ThemeContext from "../context/theme_context";

const withTheme = (OriginComp) => {
   
  return (props) => {
   
    return (
      // 将共享context传递给子组件 把传递给高阶函数的props也传递给子组件
      <ThemeContext.Consumer>
        {
   (value) => {
   
          return <OriginComp {
   ...value} {
   ...props} />;
        }}
      </ThemeContext.Consumer>
    );
  };
};

export default withTheme;

  • procuct组件
import React, {
    PureComponent } from "react";
import ThemeContext from "../context/theme_context";
import withTheme from "../hoc/with_theme";

// export class Product extends PureComponent {
   
//   render() {
   
//     return (
//       <div>
//         Product:
//         <ThemeContext.Consumer>
//           {
   
//             value => {
   
//               return <h2>theme:{value.color}-{value.size}</h2>
//             }
//           }
//         </ThemeContext.Consumer>
//       </div>
//     )
//   }
// }

// export default Product

export class Product extends PureComponent {
   
  render() {
   
    const {
    color, size, name } = this.props;

    return (
      <div>
        <h2>
          context注入的参数: {
   color}-{
   size}
        </h2>
        <div>传递给product的参数:{
   name}</div>
      </div>
    );
  }
}

// 将context的参数注入给product
export default withTheme(Product);

  • App.jsx
import React, {
    PureComponent } from "react";
import ThemeContext from "./context/theme_context";
import Product from "./pages/Product";

export class App extends PureComponent {
   
  render() {
   
    return (
      <div>
        <ThemeContext.Provider value={
   {
    color: "red", size: 30 }}>
          <Product name="kiki" />
        </ThemeContext.Provider>
      </div>
    );
  }
}

export default App;

2.4 应用2-鉴权

在这里插入图片描述

  • login_auth
const loginAuth = (OriginComp) => {
   
  return (props) => {
   
    const token = localStorage.getItem("token");
    return token ? <OriginComp {
   ...props} /> : "请先登录";
  };
};

export default loginAuth;

  • card.jsx
import React, {
    PureComponent } from 'react'
import loginAuth from '../hoc/login_auth'

export class Cart extends PureComponent {
   
  render() {
   
    return (
      <h2>Cart Page</h2>
    )
  }
}

export default loginAuth(Cart)
  • app.jsx
import React, {
    PureComponent } from "react";
import Cart from "./pages/Cart";

export class App extends PureComponent {
   
  handleClick() {
   
    localStorage.setItem("token", "kiki");

    // 修改本地缓存并不会发生界面刷新 所以需要强制刷新
    // 强制刷新在一般情况下部推荐 so 请使用 state
    this.forceUpdate();
  }
  render() {
   
    return (
      <div>
        <button onClick={
   (e) => this.handleClick()}>点击登录</button>
        <Cart />
      </div>
    );
  }
}

export default App;

2.5 应用3 – 生命周期劫持

  • log_render_time
import {
    PureComponent } from "react";

function logRenderTime(OriginComponent) {
   
  return class extends PureComponent {
   
    UNSAFE_componentWillMount() {
   
      this.beginTime = new Date().getTime()
    }
  
    componentDidMount() {
   
      this.endTime = new Date().getTime()
      const interval = this.endTime - this.beginTime
      console.log(`当前${
     OriginComponent.name}页面花费了${
     interval}ms渲染完成!`)
    }

    render() {
   
      return <OriginComponent {
   ...this.props}/>
    }
  }
}

export default logRenderTime

  • detail.jsx
import React, {
    PureComponent } from 'react'
import logRenderTime from '../hoc/log_render_time'

export class Detail extends PureComponent {
   
  // UNSAFE_componentWillMount() {
   
  //   this.beginTime = new Date().getTime()
  // }

  // componentDidMount() {
   
  //   this.endTime = new Date().getTime()
  //   const interval = this.endTime - this.beginTime
  //   console.log(`当前页面花费了${interval}ms渲染完成!`)
  // }

  render() {
   
    return (
      <div>
        <h2>Detail Page</h2>
        <ul>
          <li>数据列表1</li>
          <li>数据列表2</li>
          <li>数据列表3</li>
          <li>数据列表4</li>
          <li>数据列表5</li>
          <li>数据列表6</li>
          <li>数据列表7</li>
          <li>数据列表8</li>
          <li>数据列表9</li>
          <li>数据列表10</li>
        </ul>
      </div>
    )
  }
}

export default logRenderTime(Detail)
  • App.jsx
import React, {
    PureComponent } from 'react'
import Detail from './pages/Detail'

export class App extends PureComponent {
   
  render() {
   
    return (
      <div>
        <Detail/>
      </div>
    )
  }
}

export default App

2.6、高阶组件的意义

在这里插入图片描述

3、Portals

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4、fragment

在这里插入图片描述

import React, {
    PureComponent, Fragment } from 'react'

export class App extends PureComponent {
   
  constructor() {
   
    super() 

    this.state = {
   
      sections: [
        {
    title: "哈哈哈", content: "我是内容, 哈哈哈" },
        {
    title: "呵呵呵", content: "我是内容, 呵呵呵" },
        {
    title: "嘿嘿嘿", content: "我是内容, 嘿嘿嘿" },
        {
    title: "嘻嘻嘻", content: "我是内容, 嘻嘻嘻" },
      ]
    }
  }

  render() {
   
    const {
    sections } = this.state

    return (
      <>
        <h2>我是App的标题</h2>
        <p>我是App的内容, 哈哈哈哈</p>
        <hr />

        {
   
          sections.map(item => {
   
            return (
              <Fragment key={
   item.title}>
                <h2>{
   item.title}</h2>
                <p>{
   item.content}</p>
              </Fragment>
            )
          })
        }
      </>
    )
  }
}

export default App

5、StrictMode

在这里插入图片描述
在这里插入图片描述

6、React过渡动画实现

在这里插入图片描述
在这里插入图片描述

6.1 CSSTransition

在这里插入图片描述
在这里插入图片描述

  • npm install react-transition-group --save
    在这里插入图片描述
import React, {
    createRef, PureComponent } from "react";
import {
    CSSTransition } from "react-transition-group";
import "./style.css";

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

    this.state = {
   
      isShow: true,
    };

    // 在严格模式下会报错 所以需要绑定ref
    this.sectionRef = createRef();
  }

  render() {
   
    const {
    isShow } = this.state;

    return (
      <div>
        <button onClick={
   (e) => this.setState({
    isShow: !isShow })}>
          切换
        </button>
        {
   /* { isShow && <h2>哈哈哈</h2> } */}

        {
   /* timeout是必须要设置的,他是控制类的移出事件 动画时间还是由CSS控制 */}
        {
   /* unmountOnExit:用来决定是否移除组件 */}
        {
   /* appear:刚挂载的时候是否有动画 */}

        <CSSTransition
          nodeRef={
   this.sectionRef}
          in={
   isShow}
          unmountOnExit={
   true}
          classNames="why"
          timeout={
   2000}
          appear
          onEnter={
   (e) => console.log("开始进入动画")}
          onEntering={
   (e) => console.log("执行进入动画")}
          onEntered={
   (e) => console.log("执行进入结束")}
          onExit={
   (e) => console.log("开始离开动画")}
          onExiting={
   (e) => console.log("执行离开动画")}
          onExited={
   (e) => console.log("执行离开结束")}
        >
          <div className="section" ref={
   this.sectionRef}>
            <h2>哈哈哈</h2>
            <p>我是内容, 哈哈哈</p>
          </div>
        </CSSTransition>
      </div>
    );
  }
}

export default App;

6.2 SwitchTransition

在这里插入图片描述
在这里插入图片描述

  • App.jsx
import React, {
    PureComponent } from "react";
import {
    SwitchTransition, CSSTransition } from "react-transition-group";
import "./style.css";

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

    this.state = {
   
      isLogin: true,
    };
  }

  render() {
   
    const {
    isLogin } = this.state;

    return (
      <div>
        <SwitchTransition mode="out-in">
          <CSSTransition
            // 在切换组件的时候用的是key 显示和隐藏
            key={
   isLogin ? "exit" : "login"}
            classNames="login"
            timeout={
   1000}
          >
            <button onClick={
   (e) => this.setState({
    isLogin: !isLogin })}>
              {
   isLogin ? "退出" : "登录"}
            </button>
          </CSSTransition>
        </SwitchTransition>
      </div>
    );
  }
}

export default App;

6.3 TransitionGroup

在这里插入图片描述
在这里插入图片描述

import React, {
    PureComponent } from "react";
import {
    TransitionGroup, CSSTransition } from "react-transition-group";
import "./style.css";

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

    this.state = {
   
      books: [
        {
    id: 111, name: "你不知道JS", price: 99 },
        {
    id: 222, name: "JS高级程序设计", price: 88 },
        {
    id: 333, name: "Vuejs高级设计", price: 77 },
      ],
    };
  }

  addNewBook() {
   
    const books = [...this.state.books];
    books.push({
   
      id: new Date().getTime(),
      name: "React高级程序设计",
      price: 99,
    });
    this.setState({
    books });
  }

  removeBook(index) {
   
    const books = [...this.state.books];
    books.splice(index, 1);
    this.setState({
    books });
  }

  render() {
   
    const {
    books } = this.state;

    return (
      <div>
        <h2>书籍列表:</h2>
        <TransitionGroup component="ul">
          {
   books.map((item, index) => {
   
            return (
              // 这里不用index作为key是因为在删除的时候Index是动态变化的会发生错乱
              <CSSTransition key={
   item.id} classNames="book" timeout={
   1000}>
                <li>
                  <span>
                    {
   item.name}-{
   item.price}
                  </span>
                  <button onClick={
   (e) => this.removeBook(index)}>删除</button>
                </li>
              </CSSTransition>
            );
          })}
        </TransitionGroup>
        <button onClick={
   (e) => this.addNewBook()}>添加新书籍</button>
      </div>
    );
  }
}

export default App;

相关推荐

  1. react组件和非组件区别

    2024-02-17 02:04:02       53 阅读
  2. React基础组件传值、组件、Hook

    2024-02-17 02:04:02       57 阅读
  3. React组件详解

    2024-02-17 02:04:02       47 阅读
  4. 使用React组件

    2024-02-17 02:04:02       38 阅读
  5. react组件——withRouter

    2024-02-17 02:04:02       29 阅读
  6. React 表单、处理表单组件、非组件

    2024-02-17 02:04:02       45 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-17 02:04:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-17 02:04:02       101 阅读
  3. 在Django里面运行非项目文件

    2024-02-17 02:04:02       82 阅读
  4. Python语言-面向对象

    2024-02-17 02:04:02       91 阅读

热门阅读

  1. js 解构赋值

    2024-02-17 02:04:02       59 阅读
  2. 字节跳动CEO梁汝波:要逃逸平庸的重力

    2024-02-17 02:04:02       36 阅读
  3. Rust中打印语句为什么使用宏实现?

    2024-02-17 02:04:02       54 阅读
  4. LevelDB源码阅读笔记(0、下载编译leveldb)

    2024-02-17 02:04:02       54 阅读
  5. socket编程

    2024-02-17 02:04:02       52 阅读
  6. Selenium折线图自动化测试

    2024-02-17 02:04:02       48 阅读