Web学习笔记-React

笔记内容转载自AcWing的Web应用课讲义,课程链接:AcWing Web应用课

1. React配置环境

React官网:React

React是一个声明式,高效且灵活的用于构建用户界面的JavaScript库。使用 React 可以将一些简短、独立的代码片段组合成复杂的UI界面,这些代码片段被称作components。React能够构建那些数据会随时间改变的大型应用。

React特性:

  • React为了能够方便地去维护我们的页面,它在内存里面创建了一个虚拟的DOM树:Virtual DOM,这是一个轻量级的虚拟的DOM,就是React抽象出来的一个对象,描述DOM应该什么样子的,应该如何呈现。通过这个Virtual DOM去更新真实的DOM,由这个Virtual DOM管理真实DOM的更新。
  • 数据驱动:当某一个元素里的数据发生变化后,React会重新将有可能修改的元素都修改一遍,然后与真实的DOM树对比是否有区别,React分析完后最终只会修改真实改变的结点。由于在内存里修改对象的速度很快,因此React效率很高。
  • React一般不直接手写JS,而是通过编写JSX文件,JSX比JS更好写一点,React会先将JSX编译成JS。

(1)安装Git BashWindows安装Git教程(2022.11.18 Git2.38.1)

(2)安装NodeJSNodeJS的安装及配置

(3)安装create-react-app
打开Git bash,执行以下命令:

npm i -g create-react-app

如果速度很慢,可以先修改镜像源再尝试安装:

npm config set registry https://registry.npm.taobao.org
npm i -g create-react-app

如果安装完成后出现警告:npm WARN deprecated [email protected]: This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.,可以先更新tar试试:

npm install -g tar

如果还是有警告,且创建项目时(例如执行create-react-app react-app)报错:bash: create-react-app: command not found,使用npx创建项目:

npx create-react-app my-app

或者用npm创建项目:

npm init react-app my-app

创建好后进入项目文件夹启动项目:

cd my-app
npm start

启动后的效果如下(ctrl+c即可停止服务):

在这里插入图片描述

在这里插入图片描述

(4)配置VS Code插件:Simple React Snippets、Prettier - Code formatter
Simple React Snippets是React智能化自动补全插件:

在这里插入图片描述

例如输入imrc即可补全出以下内容:

import React, {
    
     Component } from 'react';

输入cc即可补全出以下内容:

class Example extends Component {
    
    
    state = {
    
      } 
    render() {
    
     
        return ();
    }
}
 
export default Example;

Prettier - Code formatter是代码格式化插件:

在这里插入图片描述

(5)创建React App
在目标目录下右键打开Git Bash:

在这里插入图片描述

在终端中执行:

npx create-react-app react-app  # react-app是新建项目的名字,可以替换为其他名称
cd react-app
npm start  # 启动应用

启动成功后会在本地开一个3000端口,页面效果已在上文展示。此时使用VS Code打开react-app文件夹:

在这里插入图片描述

其中,node_modules用来维护各种JS库,未来安装的所有依赖项都会放在该文件夹下;public中的index.html就是我们未来渲染出的页面,该文件中只有一个<div id="root"></div>src中的index.js代码如下:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));  // 获取div同时创建为一个React对象
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

其中App的定义在App.js中:

import logo from './logo.svg';
import './App.css';

function App() {
    
    
  return (
    <div className="App">
      <header className="App-header">
        <img src={
    
    logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

App组件就定义了页面的具体内容,且我们能够发现该JS文件中有HTML代码,因此该文件即为JSX文件,能够在JavaScript的基础上支持XML(可扩展标记语言),HTML也是一种特殊的XML。

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

2. ES6语法补充

ES6,全称ECMAScript 6.0,是JavaScript的版本标准。此处添加一些React中常用的语法糖。

(1)使用bind()函数绑定this取值
在JavaScript中,函数里的this指向的是执行时的调用者,而非定义时所在的对象。例如:

const person = {
    
    
  name: "abc",
  talk: function() {
    
    
    console.log(this);
  }
}

person.talk();

const talk = person.talk;
talk();

运行结果为:

{name: 'abc', talk: f}
undefined

使用bind()函数绑定this的取值为person。例如:

const talk = person.talk.bind(person);

运行结果为:

{name: 'abc', talk: f}
{name: 'abc', talk: f}

(2)箭头函数的简写方式
当函数参数只有一个时可以将括号去掉,当函数体只有一个return语句时可以把return{}一起去掉,例如:

const f = (x) => {
    
    
  return x * x;
};

等价于:

const f = x => x * x;

(3)箭头函数不重新绑定this的取值

const person = {
    
    
  talk: function() {
    
    
    setTimeout(function() {
    
    
      console.log(this);
    }, 1000);
  }
};

person.talk();  // 输出Window
const person = {
    
    
  talk: function() {
    
    
    setTimeout(() => {
    
    
      console.log(this);
    }, 1000);
  }
};

person.talk();  // 输出 {talk: f}

(4)对象的解构

const person = {
    
    
  name: "abc",
  age: 18,
  height: 180,
};

const {
    
    name : new_name, age} = person;  // new_name是name的别名

(5)数组和对象的展开

let a = [1, 2, 3];
let b = [...a];  // b是a的复制,和a不是一个数组,如果写let b = a则b和a是同一个数组
let c = [...a, 4, 5, 6];  // c = [1, 2, 3, 4, 5, 6]

let d = {
    
    name: "abc"};
let e = {
    
    age: 18, height: 180};
let f = {
    
    ...d, ...e, weight: 120};  // f = {name: "abc", age: 18, height: 180, weight: 120}

(6)Named exports与Default exports

  • Named Export:可以export多个,import的时候需要加大括号,名称需要匹配,即之前使用的方式。
  • Default Export:最多export一个,import的时候不需要加大括号,可以直接定义别名。

3. Components

(1)创建项目
首先创建一个新项目box-app

npx create-react-app box-app
cd box-app
npm start

安装bootstrap库:

npm i bootstrap

bootstrap的引入方式:

import 'bootstrap/dist/css/bootstrap.css';

(2)创建Component
src文件夹中创建一个文件夹components存放组件,然后在components文件夹中创建一个JSX文件box.jsx(使用.js后缀也一样,只是用.jsx后区分起来跟明显一点)其框架如下:

import React, {
    
     Component } from 'react';  // 输入imrc即可补全

class Box extends Component {
    
      // 输入cc即可补全
    state = {
    
      } 
    render() {
    
      // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
        return (<h1>Hello World!</h1>);
    }
}
 
export default Box;

然后我们需要在index.js中将组件渲染出来:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import 'bootstrap/dist/css/bootstrap.css';
import Box from './components/box';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Box />
  </React.StrictMode>
);

(3)创建按钮
由于Component中的render()函数只能return一个元素,因此当子节点数量大于1时,可以用<div><React.Fragment>将其括起来。

(4)内嵌表达式
JSX中使用{}在HTML标签中嵌入表达式。

(5)设置属性
由于class是JS中的关键字,因此HTML标签中的class需要改为className。CSS属性也需要修改,例如:background-color修改为backgroundColor,其它属性也是类似的。

综合示例:

import React, {
    
     Component } from 'react';  // 输入imrc即可补全

class Box extends Component {
    
      // 输入cc即可补全
    state = {
    
     
        x: 0
    };

    styles = {
    
    
        width: '50px',
        height: '50px',
        backgroundColor: 'lightblue',
        color: 'white',
        textAlign: 'center',
        lineHeight: '50px',
        borderRadius: '5px'
    };

    render() {
    
      // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
        return (
        // HTML标签中可以使用{}写一个表达式
        <React.Fragment>
            <div style={
    
    this.styles}>{
    
    this.state.x}</div>
            <button className='btn btn-primary m-2'>Left</button>
            <button className='btn btn-success m-2'>Right</button>
        </React.Fragment>
        );
    }
}
 
export default Box;

(6)数据驱动改变Style
例如:

import React, {
    
     Component } from 'react';  // 输入imrc即可补全

class Box extends Component {
    
      // 输入cc即可补全
    state = {
    
     
        x: 1
    };

    render() {
    
      // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
        return (
        // HTML标签中可以使用{}写一个表达式
        <React.Fragment>
            <div style={
    
    this.getStyles()}>{
    
    this.state.x}</div>
            <button className='btn btn-primary m-2'>Left</button>
            <button className='btn btn-success m-2'>Right</button>
        </React.Fragment>
        );
    }

    getStyles() {
    
    
        let styles = {
    
    
            width: '50px',
            height: '50px',
            backgroundColor: 'lightblue',
            color: 'white',
            textAlign: 'center',
            lineHeight: '50px',
            borderRadius: '5px'
        };

        if (this.state.x === 0) {
    
    
            styles.backgroundColor = 'orange';
        }

        return styles;
    }
}
 
export default Box;

(7)渲染列表
可以使用map函数渲染一个列表,每个元素需要具有唯一的key属性,用来帮助React快速找到被修改的DOM元素,例如:

import React, {
    
     Component } from 'react';  // 输入imrc即可补全

class Box extends Component {
    
      // 输入cc即可补全
    state = {
    
     
        x: 1,
        colors: ['red', 'green', 'blue']
    };

    render() {
    
      // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
        return (
        // HTML标签中可以使用{}写一个表达式
        <React.Fragment>
            <div>{
    
    this.state.x}</div>
            <button className='btn btn-primary m-2'>Left</button>
            <button className='btn btn-success m-2'>Right</button>
            {
    
    this.state.colors.map(color => (
                <div key={
    
    color}>{
    
    color}</div>
            ))}
        </React.Fragment>
        );
    }
}
 
export default Box;

(8)Conditional Rendering
利用逻辑表达式的短路原则:

  • 与表达式中expr1 && expr2,当expr1为假时返回expr1的值,否则返回expr2的值。
  • 或表达式中expr1 || expr2,当expr1为真时返回expr1的值,否则返回expr2的值。

(9)绑定事件
例如可以使用onClick绑定按钮的点击事件,注意需要妥善处理好绑定事件函数的this,示例如下:

import React, {
    
     Component } from 'react';  // 输入imrc即可补全

class Box extends Component {
    
      // 输入cc即可补全
    state = {
    
     
        x: 1
    };

    handleClickLeft() {
    
      // 如果不用箭头函数或者下面调用函数时使用bind(this)的话this会变成undefined
        console.log('click left', this);
    }

    handleClickRight = () => {
    
    
        console.log('click right', this);
    }

    render() {
    
      // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
        return (
        // HTML标签中可以使用{}写一个表达式
        <React.Fragment>
            <div>{
    
    this.state.x}</div>
            <button onClick={
    
    this.handleClickLeft} className='btn btn-primary m-2'>Left</button>
            <button onClick={
    
    this.handleClickRight} className='btn btn-success m-2'>Right</button>
        </React.Fragment>
        );
    }
}
 
export default Box;

(10)修改state
需要使用this.setState()函数,每次调用this.setState()函数后,会重新调用this.render()函数,用来修改虚拟DOM树。React只会修改不同步的实际DOM树节点。例如:

import React, {
    
     Component } from 'react';  // 输入imrc即可补全

class Box extends Component {
    
      // 输入cc即可补全
    state = {
    
     
        x: 1
    };

    handleClickLeft = () => {
    
    
        // this.state.x--;  这样写的话React不会修改前端页面的效果
        this.setState({
    
    
            x: this.state.x - 1
        });
    }

    handleClickRight = () => {
    
    
        this.setState({
    
    
            x: this.state.x + 1
        });
    }

    render() {
    
      // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
        return (
        // HTML标签中可以使用{}写一个表达式
        <React.Fragment>
            <div style={
    
    this.getStyles()}>{
    
    this.state.x}</div>
            <button onClick={
    
    this.handleClickLeft} className='btn btn-primary m-2'>Left</button>
            <button onClick={
    
    this.handleClickRight} className='btn btn-success m-2'>Right</button>
        </React.Fragment>
        );
    }

    getStyles() {
    
    
        let styles = {
    
    
            width: '50px',
            height: '50px',
            backgroundColor: 'lightblue',
            color: 'white',
            textAlign: 'center',
            lineHeight: '50px',
            borderRadius: '5px',
            position: 'relative',
            left: this.state.x
        };

        if (this.state.x === 0) {
    
    
            styles.backgroundColor = 'orange';
        }

        return styles;
    }
}
 
export default Box;

(11)给事件函数添加参数
可以定义一个临时函数绑定事件,然后在该函数中调用原函数并传入参数,或者直接在绑定事件的时候用一个临时的箭头函数返回传入参数的原函数。例如:

import React, {
    
     Component } from 'react';  // 输入imrc即可补全

class Box extends Component {
    
      // 输入cc即可补全
    state = {
    
     
        x: 1
    };

    handleClickLeft = (step) => {
    
    
        this.setState({
    
    
            x: this.state.x - step
        });
    }

    handleClickRight = (step) => {
    
    
        this.setState({
    
    
            x: this.state.x + step
        });
    }

    handleClickLeftTmp = () => {
    
    
        this.handleClickLeft(10);
    }

    render() {
    
      // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
        return (
        // HTML标签中可以使用{}写一个表达式
        <React.Fragment>
            <div style={
    
    this.getStyles()}>{
    
    this.state.x}</div>
            <button onClick={
    
    this.handleClickLeftTmp} className='btn btn-primary m-2'>Left</button>
            <button onClick={
    
    () => this.handleClickRight(10)} className='btn btn-success m-2'>Right</button>
        </React.Fragment>
        );
    }

    getStyles() {
    
    
        let styles = {
    
    
            width: '50px',
            height: '50px',
            backgroundColor: 'lightblue',
            color: 'white',
            textAlign: 'center',
            lineHeight: '50px',
            borderRadius: '5px',
            position: 'relative',
            left: this.state.x
        };

        if (this.state.x === 0) {
    
    
            styles.backgroundColor = 'orange';
        }

        return styles;
    }
}
 
export default Box;

猜你喜欢

转载自blog.csdn.net/m0_51755720/article/details/127922719
今日推荐