菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
0
0

【初识React框架】React 核心概念

原创
05/13 14:22
阅读数 158

一、React 介绍

1. 产生背景:

◆ React 是用于构建用户界面的 JavaScript 库,起源于 Facebook 的内部项目,该公司对市场上所有 JavaScript MVC框架都不满意,决定自行开发一套,用于架设 Instagram 的网站,于2013年5月开源。
◆ 由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。
◆ 这个项目本身也越滚越大,从最早的UI引擎变成了一整套前后端通吃的 Web App解决方案。衍生的 React Native 项目,目标更是宏伟,希望用写 Web App 的方式去写 Native App。如果能够实现,整个互联网行业都会被颠覆,因为同一组人只需要写一次UI ,就能同时运行在服务器、浏览器和手机。

2. 用途:

◆ React 主要用于构建UI。你可以在 React 里传递多种类型的参数,如声明代码,帮助你渲染出UI、也可以是静态的 HTML DOM 元素、也可以传递动态变量、甚至是可交互的应用组件。

3. 特点:

◆ 声明式设计:React 使创建交互式 UI 变得轻而易举。为你应用的每一个状态设计简洁的视图,当数据变动时 React 能高效更新并渲染合适的组件。
◆ 组件化: 构建管理自身状态的封装组件,然后对其组合以构成复杂的 UI。
◆ 高效:React 通过对 DOM 的模拟(虚拟 DOM 树),最大限度地减少与 DOM 的交互(只修改不一样的部分)
◆ 灵活:无论你现在使用什么技术栈,在无需重写现有代码的前提下,通过引入 React 来开发新功能。

4. JSX:

JSX 是 React 中的一种语言,会被 Babel 编译成标准 JavaScript

二、React 环境配置

1. 配置环境:

◆ 终端环境(三选一): Git (推荐)、 window的PowerShell 、 VS Code中按下 Ctrl+ `
◆ Node.js环境

2. 创建 React App:

选定一个目录执行如下操作,推荐使用 React 官方的脚手架 create-react-app 创建项目
◆ 创建 React 项目:npx create-react-app project-name --typescript,project-name 为项目名称,–typescript 代表是否使用TS
◆ 到项目文件夹下:cd project-name
◆ 启动 React 项目:npm start

3. VS Code插件:

◆ Simple React Snippets:自动补全一些 React 常用代码
◆ Prettier - Code formatter:代码格式化与高亮

4. 第三方库(可选):

bootstrap:
◆ 安装:npm i bootstrap
◆ 引入CSS:import ‘bootstrap/dist/css/bootstrap.css’;
◆ 引入JS:import “bootstrap/dist/js/bootstrap.js”;

三、组件(component)

1. 引入组件库:

使用 Simple React Snippets 插件快捷生成 imrc + Tab

import React, { Component } from "react";

2. JSX简介 :

◆ 嵌入表达式:{},可以在大括号内放置任何有效的 JavaScript 表达式(变量)

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;

注意:
◆ 自闭标签必须以斜杠结尾,例如
◆ 属性和方法必须采用驼峰式,例如 onClick
◆ 添加CSS类使用 className,因为 class 是 Javascript 里的关键字
◆ CSS属性中用 - 链接的改为驼峰式,例如 background-color -> backgroundColor

3. 类组件:

使用 Simple React Snippets 插件快捷生成 cc + Tab

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

4. 函数式组件:

使用 Simple React Snippets 插件快捷生成 sfc + Tab

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

5. 使用组件:

render() 函数最终只能返回一个标签,当子节点数量大于1时,可以用 <div> 或<React.Fragment> 将其括起来
import React, { Component } from "react";  //引入组件库
import TestCard1 from "../components/TestCard1";  //引入写好的组件
import TestCard2 from "../components/TestCard2";  //引入写好的组件

class Test extends React.Component {	//类组件
  render() {
    return (
      <React.Fragment>
        <h1>Test</h1>
        <TestCard1 />	//使用写好的组件
        <TestCard2 />	//使用写好的组件
      </React.Fragment>
    );
  }
}

export default Test;

效果如下:
图片.png

四、渲染列表(map)

1. Key 属性:

◆ 每个元素需要具有唯一的 key 属性,用来帮助 React 快速找到被修改的 DOM 元素,通常使用数据中的 id 来作为元素的 key,即一个独一无二的字符串
◆ 当元素没有确定 id 的时候,可以使用元素索引 index 作为 key,如果列表项目的顺序可能会变化,不建议使用索引来用作 key 值,因为这样做会导致性能变差,还可能引起组件状态的问题。

2. 示例:

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>	//将 numbers 中的每一个数字 number 转化成一个列表 li
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<NumberList numbers={numbers} />);

五、数据传输(state、props)

1. 单向数据流:

◆ state 中的数据相当于类中的私有变量,可以通过 props(传递数据)、 props.children (传递子节点)向下传递到子组件中,但是只能在当前组件的内部通过 setState() 函数修改,不能在子组件内修改
◆ 子组件中不应该存在任何修改 state 数据的函数,应提升至父组件,再通过 props 调用
◆ 多个组件共用的数据应存放到最近公共祖先的 state 中
◆ 每次调用 setState() 函数后,会重新调用 render() 函数,用来修改内存中的虚拟 DOM 树,然后修改实际 DOM 树中不同步的节点。

2. 事件处理:

◆ 绑定事件函数:使用 bind() 将函数绑定,或者将函数定义为箭头函数
◆ 阻止默认行为:preventDefault()

    function Form() {
      function handleSubmit(e) {
        e.preventDefault();
        console.log('You clicked submit.');
      }

      return (
        <form onSubmit={handleSubmit}>
          <button type="submit">Submit</button>
        </form>
      );
    }

3. 示例:

通过子组件 Round(圆球)和父组件 Rounds(圆球组)说明
Rounds 组件:

import React, { Component } from "react";	 //引入组件库
import Round from "./Round"; 	//引入子组件圆球 Round

//定义 Rounds 组件
class Rounds extends React.Component {
  state = {									 //通过 state 定义圆球块中的私有变量
    Rounds: [
      { id: 1, r: 100 },
      { id: 2, r: 100 },
      { id: 3, r: 100 },
      { id: 4, r: 100 },
    ],
  };
  //使用 bind() 将函数绑定,或者将函数定义为箭头函数
  //this.increaseRoundRadius = this.increaseRoundRadius.bind(this); 
  increaseRoundRadius = (roundId, step) => { //定义变大函数
    const Rounds = this.state.Rounds;
    for (let round of Rounds) {
      if (round.id === roundId) {
        round.r += step;
      }
    }
    this.setState({	//修改 state 中的数据需要通过 setState 方法,不能直接修改
      Rounds,  // ES6 语法糖,当属性和值一样时可以简写,参考文章 Javascript(上)
    });
  };

  decreaseRoundRadius = (roundId, step) => { //定义变小函数
    const Rounds = this.state.Rounds;
    for (let round of Rounds) {
      if (round.id === roundId) {
        round.r -= step;
      }
    }
    this.setState({ //修改 state 中的数据需要通过 setState 方法,不能直接修改
      Rounds,
    });
  };

  handleDelete = (RoundId) => { //定义删除函数
 	//filter函数,筛选数组中符合条件的元素
    const Rounds = this.state.Rounds.filter((round) => round.id !== RoundId);	//相当于删除传入的 id 元素
    this.setState({ Rounds: Rounds });	//修改 state 中的数据需要通过 setState 方法,不能直接修改
  };

  render() {
    return (
      <React.Fragment>
        <div>
          {this.state.Rounds.map((round) => (	//使用 map 渲染列表,将 State 数组Rounds 中的每一项round 渲染成如下内容
            <Round
              key={round.id}	//调用数组Rounds 中的每一项的id、r
              r={round.r}
              id={round.id}
              onDelete={this.handleDelete}	//调用方法
              increaseRadius={this.increaseRoundRadius}
              decreaseRadius={this.decreaseRoundRadius}
            >
              <h1>Round:</h1>			//传递标签给子组件
              <p>这是第{round.id}个</p>		//传递标签给子组件
            </Round>
          ))}
        </div>
      </React.Fragment>
    );
  }
}

export default Rounds;

Round 组件:

import React, { Component } from "react";  //引入组件库

//定义 Round 组件
class Round extends React.Component {
  render() {
    return (
      <React.Fragment>
        <div									//圆球块的一些样式设置,可以忽略
          style={{
            display: "inline-block",
            margin: 50,
          }}
        >
        
          //通过 props.children 调用父组件中 Round 内的圆球组标签 h1
          {this.props.children[0]}
          <div									//圆球的一些样式设置,可以忽略
            style={{
              margin: "50px 50px 0px 60px",
              height: this.props.r,
              width: this.props.r,
              borderRadius: "50%",
              backgroundColor: "aqua",
              textAlign: "center",
              lineHeight: this.props.r / 17,
            }}
          >
          
          //通过 props 调用父组件中 Round 的 r 属性,进而调用圆球组 state 中的数据 r
          {`R:${this.props.r}`}			
          </div>
          
          //通过 props.children 调用父组件中 Round 内的圆球组标签 p
          {this.props.children[1]}			
          
          //通过 props 调用父组件中 Round 的 increaseRadius 属性,进而调用圆球组中的变大函数 increaseRadius
          <button							
            onClick={() => this.props.increaseRadius(this.props.id, 10)} //定义点击事件,使用箭头函数传参数
            className="btn btn-outline-primary m-2"
          >
            变大
          </button>
          
          //通过 props 调用父组件中 Round 的 decreaseRadius 属性,进而调用圆球组中的变小函数 decreaseRadius
          <button							
            onClick={() => this.props.decreaseRadius(this.props.id, 10)} //定义点击事件,使用箭头函数传参数
            className="btn btn-outline-success m-2"
          >
            变小
          </button>
          
          //通过 props 调用父组件中 Round 的 onDelete 属性,进而调用圆球组中的删除函数 onDelete
          <button
            onClick={() => this.props.onDelete(this.props.id)}	//定义点击事件,使用箭头函数传参数
            className="btn btn-outline-danger m-2"
          >
            删除
          </button>
        </div>
      </React.Fragment>
    );
  }
}

export default Round;

效果如下:
图片.png

六、生命周期

1. 生命周期方法 :

◆ 挂载(mount):componentDidMount() {},当组件第一次被渲染到 DOM 中的时候执行
◆ 更新(update):componentDidUpdate() {},当组件在 DOM 中更新的时候执行
◆ 卸载(unmount):componentWillUnmount() {},当组件从 DOM 中删除的时候执行

2. 执行顺序:

◆ Mount 周期:constructor() -> render() -> componentDidMount(),即构造、渲染、挂载
◆ Update 周期:render() -> componentDidUpdate(),即渲染、更新
◆ Unmount 周期:componentWillUnmount(),卸载

发表评论

0/200
0 点赞
0 评论
收藏