React初印象

2024-09-10  本文已影响0人  zhengxiaolang

听过哪些与React相关的名词:


dom5.png

今天主要介绍:React 18.3
以下分享源码在此

1、虚拟 DOM(Virtual DOM):

React 使用虚拟 DOM 渲染流程。


dom1.png
 <body>
  <div id="root"></div>
  <!-- 引入React.js -->
  <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
  <!-- 引入ReactDOM.js -->
  <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>

  <script src="https://unpkg.com/babel-standalone/babel.min.js"></script>

  <script type="text/babel">

    function handleClick() {
      alert('Div element clicked!');
    }

     //React.createElement是React官方提供创建虚拟dom的一个api.
    const element = React.createElement(
      'div',
      { className: 'redBg', onClick: handleClick },
      'Item 1'
    );

//JSX语法,经过Babel编译器,转化成React.createElement()
   const element2 = (
      <div className="redBg" onClick={handleClick}>
        Item 1
      </div>
    );

    //将虚拟 DOM(React 元素)渲染到真实 DOM 的过程: 1.获取页面元素-->2.创建容器-->3.将虚拟元素渲染到容器内

    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(element);

    const realDom = document.getElementById('realDom');

    console.log('virtualDom', element);
    console.log('realDom', realDom);

  </script>
</body>
dom3.png
虚拟dom总结:
- 本质:JS对象,相对真实dom,相对真实dom是一个轻量级的对象。

- 优点:
1、最小化真实dom操作,减少重绘(Repaint)和重排(Reflow)次数。

   重排:受DOM的布局、尺寸、位置等发生变化时影响
   重绘:受DOM的外观(如颜色、边框、背景)发生变化时影响

2、快速开发,组件复用。

- 缺点:多一份虚拟dom内存开销。

2、JSX:

JSX是一种用于描述 UI 的JavaScript 语法扩展,允许在 JavaScript 中编写类似 HTML 的代码。
编译器Babel将jsx代码编译成React.createElement。


dom4.png
const element = <h1>Hello, world!</h1>;

const element2 = (
    <div className="redBg" onClick={handleClick}>
        muplti line
      </div>
   );
const itemName = 'Item 2';
const element3 = (
    <div className="redBg" onClick={handleClick}>
        {itemName}
      </div>
   );
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'];
const element = (
  <div className="fruit-list">
    <h1>Fruit List</h1>
    <ul>
      {items.map((item, index) => (
        <li key={index} className="fruit-item">
          {item}
        </li>
      ))}
    </ul>
    <footer>
      <p>Total items: {items.length}</p>
    </footer>
  </div>
);
// 渲染到页面
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);
错误写法:
const element = (
    <h1>Hello</h1>
    <p>This is a paragraph.</p>
   );
纠正写法:
const element = (
  <React.Fragment>
    <h1>Hello</h1>
    <p>This is a paragraph.</p>
  </React.Fragment>
);
简易写法:
const element = (
  <React.Fragment>
    <h1>Hello</h1>
    <p>This is a paragraph.</p>
  </React.Fragment>
);
总结:
<> ... </> = <React.Fragment>... </React.Fragment>

而在angular中,刚好相反,是在HTML 的代码编写js代码

<div>
  <p>{{ message }}</p>
  <button (click)="updateMessage()">Click me</button>
</div>

3、组件(Component):

React 的核心概念,UI 的构建块。组件可以是函数组件或类组件

class ClassComponent extends Component {
    constructor(props) {
        super(props);
        // 初始化 state
        this.state = {
            count: 0,
        };
    }

    componentDidMount() {
        // 组件挂载后调用
        console.log('Component did mount');
    }

    shouldComponentUpdate(nextProps, nextState) {
        // 控制组件是否需要重新渲染
        return nextState.count !== this.state.count;
    }

    componentDidUpdate(prevProps, prevState) {
        // 组件更新后调用
        console.log('Component did update');
    }

    componentWillUnmount() {
        // 组件卸载之前调用
        console.log('Component will unmount');
    }

    render() {
        return (
            <div>
                <p>Count: {this.state.count}</p>
                <button onClick={this.handleClick}>Increment</button>
            </div>
        );
    }
}

ClassComponent.propTypes = {
    name: PropTypes.string.isRequired,
    age: PropTypes.number,
    onValueChange: PropTypes.func,
};

export default ClassComponent;
import React from 'react'
import './Style.css';
function FCComponent() {
  return (
    <div className='bg-yellow center'>这是函数组件</div>
  )
}

export default FCComponent

3、状态(State):

1.是组件内部的状态。
2.可变,通常在组件内部管理和更新。
3.用于管理组件自身的数据和状态。

constructor(props) {
    super(props);
    // 初始化 state
    this.state = {
          count: 0,
           name: '',
           age: 0
        };
}
const [count, setCount] = useState(0);
const [name, setName] = useState('');
const [age, setAge] = useState(0);

4、属性(Props):

1.是组件的属性,用于从父组件传递数据和回调函数。
2.不可变,子组件不能直接修改。
3.用于将数据和功能从父组件传递到子组件。

function Welcome(props) {
  return <h1>Hello, {props.name}!</h1>;
}

5、生命周期方法(Lifecycle Methods):

类组件中特定的钩子函数,用于在组件的不同阶段执行代码,如 componentDidMount、componentDidUpdate 和 componentWillUnmount。

class ComponentA extends Component {
  constructor(props) {
    super(props);
    this.state = {
      // 初始化 state
    };
  }

  static getDerivedStateFromProps(nextProps, prevState) {
    // 用于根据新的 props 更新 state
    return null;
  }

  componentDidMount() {
    // 组件挂载后调用
  }

  shouldComponentUpdate(nextProps, nextState) {
    // 控制组件是否需要重新渲染
    return true;
  }

  static getSnapshotBeforeUpdate(prevProps, prevState) {
    // 在更新之前获取快照
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // 组件更新后调用
  }

  componentWillUnmount() {
    // 组件卸载之前调用
  }

  render() {
    return (
      <div>
        {/* 组件内容 */}
      </div>
    );
  }
}
ComponentA .propTypes = {
  // 定义 prop 类型
};

export default Second;

6、Hooks:

React 16.8 引入的特性,允许在函数组件中使用状态和其他 React 特性,如 useState 和 useEffect。


dom6.png

7、组件通讯:

dom7.png
pubsub使用:
安装
(1) npm install pubsub-js --save
导入
(2) import PubSub from "pubsub-js"

class Publisher extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        num: 0
      };
    }
    componentDidMount() {  
      // 假设我们在组件挂载后发布一个事件
      setInterval(() => {
        PubSub.publish('someChannel', { message: 'Hello from Publisher!'+ this.state.num }); 
        this.setState({
          num: this.state.num + 1
        });
  
      }, 1000);
    } 
    
    render() {  
      return <div>Publisher Component</div>;  
    }  
  }  
    
  class Subscriber extends React.Component {  
    componentDidMount() {  
      // 订阅事件  
      this.token = PubSub.subscribe('someChannel', (msg, data) => {  
        console.log(data.message, msg); // 输出: Hello from Publisher!  
      });  
    }  
    
    componentWillUnmount() {  
      // 组件卸载时取消订阅,防止内存泄漏  
      PubSub.unsubscribe(this.token);
    }  
    
    render() {  
      return <div>Subscriber Component</div>;  
    }  
  }  

8、上下文(Context):

用于在组件树中传递数据,而不需要通过每层组件手动传递 props

import React, { createContext, Component } from 'react';

// 创建一个 Context 对象
const MyContext = createContext();

// 创建一个提供 Context 的组件
class MyProvider extends Component {
    state = {
        user: {
            name: 'Alice',
            age: 30
        }
    };

    setUser = (name, age) => {
        this.setState({
            user: { name, age }
        });
    };

    render() {
        return (
            <MyContext.Provider value={{ 
                user: this.state.user,
                setUser: this.setUser
            }}>
                {this.props.children}
            </MyContext.Provider>
        );
    }
}
import React, { Component } from 'react';

// 创建一个消费 Context 的组件
class ChildComponent extends Component {
    static contextType = MyContext;

    handleChangeUser = () => {
        const { setUser } = this.context;
        setUser('Bob', 25);
    };

    render() {
        const { user } = this.context;
        return (
            <div>
                <p>User Name: {user.name}</p>
                <p>User Age: {user.age}</p>
                <button onClick={this.handleChangeUser}>Change User</button>
            </div>
        );
    }
}

// 创建一个消费 Context 的组件
class Child2Component extends Component {
    static contextType = MyContext;

    handleChangeUser = () => {
        const { setUser } = this.context;
        setUser('Bob--22', 250);
    };

    render() {
        const { user } = this.context;
        return (
            <div>
                <p>User Name: {user.name}</p>
                <p>User Age: {user.age}</p>
                <button onClick={this.handleChangeUser}>Change User</button>
            </div>
        );
    }
}

// 创建一个顶层父组件
class ParentContextComponent extends Component {
    render() {
        return (
            <MyProvider>
                <div className='center'>
                    <h1>上下文Context Component</h1>
                    <ChildComponent />
                    <br/>
                    <Child2Component />
                </div>
            </MyProvider>
        );
    }
}

export default ParentContextComponent;

9、Redux:

一个流行的状态管理库,常与 React 一起使用,帮助管理应用的全局状态。
由于内容比较多,下次再专门做个分享会。

10、插槽:

先来看一段angular的代码

先定义一个包含插槽的组件container.component:

<div class="parent">
  <h1>Parent Component</h1>
  <!-- 第一个插槽 -->
  <ng-content select="[header]"></ng-content>
  <hr/>
  <!-- 第二个插槽 -->
  <ng-content select="[body]"></ng-content>
  <hr/>
  <!-- 第三个插槽 -->
  <ng-content select="[footer]"></ng-content>
</div>

调用container.component,插入需要不同位置的代码

<!-- app.component.html -->
<app-parent>
  <div header>
    <h2>This is the Header Content</h2>
  </div>
  <div body>
    <p>This is the Body Content</p>
  </div>
  <div footer>
    <p>This is the Footer Content</p>
  </div>
</app-parent>
下面再看一下React的代码

先定义一个包含插槽的组件container.component:

import React, { Component } from 'react';

class ParentComponent extends Component {
  render() {
    const { header, body, footer } = this.props;
    return (
      <div className="parent">
        <h1>Parent Component</h1>
        {/* 渲染不同的插槽内容 */}
        <div className="header">{header}</div>
        <hr/>
        <div className="body">{body}</div>
        <hr/>
        <div className="footer">{footer}</div>
      </div>
    );
  }
}

export default ParentComponent;

将内容作为 props 传递给 ParentComponent 的不同插槽

import React, { Component } from 'react';
import ParentComponent from './ParentComponent';

class App extends Component {
  render() {
    return (
      <ParentComponent
        header={<h2>This is the Header Content</h2>}
        body={<p>This is the Body Content</p>}
        footer={<p>This is the Footer Content</p>}
      />
    );
  }
}

export default App;

以上是本次分享,谢谢大家。

上一篇下一篇

猜你喜欢

热点阅读