React 基础

文章目录

  • React是什么?
  • [1. JSX 简介](#1. JSX 简介)
    • [1.1 在 JSX 中嵌入表达式](#1.1 在 JSX 中嵌入表达式)
    • [1.2 JSX 中指定属性](#1.2 JSX 中指定属性)
    • [1.3 使用 JSX 指定子元素](#1.3 使用 JSX 指定子元素)
    • [1.4 JSX 表示对象](#1.4 JSX 表示对象)
  • [2. 元素渲染](#2. 元素渲染)
      • [2.1 将一个元素渲染为 DOM](#2.1 将一个元素渲染为 DOM)
  • [3. 组件 & Props](#3. 组件 & Props)
    • [3.1 函数组件与class组件](#3.1 函数组件与class组件)
      • [3.1.1 函数组件](#3.1.1 函数组件)
      • [3.1.2 class组件](#3.1.2 class组件)
      • [3.2 渲染组件 & props](#3.2 渲染组件 & props)
    • [3.1 Props的只读性](#3.1 Props的只读性)
  • [4. State & 生命周期](#4. State & 生命周期)
    • [4.1 class 组件中的 state](#4.1 class 组件中的 state)
      • [4.2 class组件中的生命周期](#4.2 class组件中的生命周期)
    • [4.3 正确使用State](#4.3 正确使用State)
      • [4.3.1 不要直接修改 State](#4.3.1 不要直接修改 State)
      • [4.3.2 State 的更新可能是异步的](#4.3.2 State 的更新可能是异步的)
      • [4.3.3 State 的更新会被合并](#4.3.3 State 的更新会被合并)
    • [4.4 数据是向下流动的](#4.4 数据是向下流动的)
  • [5. 事件处理](#5. 事件处理)
    • [5.1 基本使用](#5.1 基本使用)
    • [5.2 class组件中的this问题](#5.2 class组件中的this问题)
      • [5.2.1 使用bind来解决this问题](#5.2.1 使用bind来解决this问题)
      • [5.2.2 使用类字段来解决this问题(常用)](#5.2.2 使用类字段来解决this问题(常用))
      • [5.2.3 回调中使用箭头函数解决this问题](#5.2.3 回调中使用箭头函数解决this问题)
    • [5.3 向事件处理程序传递参数](#5.3 向事件处理程序传递参数)
  • [6. 条件渲染](#6. 条件渲染)
    • [6.1 `if` 语句进行条件渲染](#6.1 if 语句进行条件渲染)
    • [6.2 与运算符 &&](#6.2 与运算符 &&)
    • [6.3 三目运算符](#6.3 三目运算符)
  • [7. 列表 & Key](#7. 列表 & Key)
    • [7.1 基础列表组件](#7.1 基础列表组件)
    • [7.2 key](#7.2 key)
  • [8. 表单](#8. 表单)
    • [8.1 受控组件](#8.1 受控组件)
    • [8.2 处理多个输入](#8.2 处理多个输入)
  • [9. 状态提升](#9. 状态提升)
  • [10. 组合 vs 继承](#10. 组合 vs 继承)
    • [10.1 包含关系](#10.1 包含关系)
  • [11. 样式](#11. 样式)
    • [11.1 行内样式](#11.1 行内样式)
    • [11.2 class 类名](#11.2 class 类名)

React是什么?

用于构建用户界面的 JavaScript 库

1. JSX 简介

1.1 在 JSX 中嵌入表达式

声明变量 name,并包裹在大括号中

js 复制代码
const name = 'world';
const element = <h1>Hello, {name}</h1>;

在 JSX 语法中,你可以在大括号内放置任何有效的 JavaScript 表达式

1.2 JSX 中指定属性

可以使用大括号,来在属性值中插入一个 JavaScript 表达式:

js 复制代码
const element = <img src={user.avatarUrl}></img>;

1.3 使用 JSX 指定子元素

JSX 标签里能够包含很多子元素:

js 复制代码
const element = (
  <div>
    <h1>Hello!</h1>
    <h2>Good to see you here.</h2>
  </div>
);

1.4 JSX 表示对象

js 复制代码
const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

等效于:

js 复制代码
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

2. 元素渲染

2.1 将一个元素渲染为 DOM

页面根节点

html 复制代码
<div id="root"></div>

将一个 React 元素渲染到根 DOM 节点中,只需把它们一起传入

js 复制代码
const root = ReactDOM.createRoot(
  document.getElementById('root')
);

const element = <h1>Hello, world</h1>;

root.render(element);

3. 组件 & Props

组件允许你将 UI 拆分为独立可复用的代码片段,并对每个片段进行独立构思

3.1 函数组件与class组件

注意:组件名称必须以大写字母开头

3.1.1 函数组件

接受任意的入参(即 "props")

js 复制代码
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

3.1.2 class组件

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

3.2 渲染组件 & props

当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 "props"

js 复制代码
const element = <Welcome name="Sara" />;

子组件(children)例子:

js 复制代码
<Welcome name="react">
  <span>children</span>
</Welcome>

最终props为

js 复制代码
{name: 'react', children: {...}}

3.1 Props的只读性

组件无论是使用 函数声明还是通过 class 声明,都决不能修改自身的 props

纯函数:函数不会尝试更改入参,且多次调用下相同的入参始终返回相同的结果。

如:

js 复制代码
function sum(a, b) {
  return a + b;
}

相反,下面这个则不是纯函数

js 复制代码
function withdraw(account, amount) {
  account.total -= amount;
}

所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。

4. State & 生命周期

4.1 class 组件中的 state

js 复制代码
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

4.2 class组件中的生命周期

componentDidMount:方法会在组件已经被渲染到 DOM 中后运行
componentWillUnmount:方法会在组件卸载前调用

js 复制代码
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
  }

  componentWillUnmount() {
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

4.3 正确使用State

4.3.1 不要直接修改 State

例如,此代码不会重新渲染组件:

js 复制代码
// 错误
this.state.comment = 'Hello';

而是应该使用 setState():

js 复制代码
// 正确
this.setState({comment: 'Hello'});

构造函数是唯一可以给 this.state 赋值的地方。

4.3.2 State 的更新可能是异步的

出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。

因为 this.propsthis.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。

比如:

js 复制代码
// 错误
this.setState({
  counter: this.state.counter + this.props.increment,
});

解决这个问题:

可以让 setState() 接收一个函数而不是一个对象

js 复制代码
// Correct
this.setState((state, props) => ({
  counter: state.counter + props.increment
}));

4.3.3 State 的更新会被合并

当你调用 setState() 的时候,React 会把你提供的对象合并到当前的 state。

4.4 数据是向下流动的

5. 事件处理

5.1 基本使用

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

示例:

js 复制代码
function MyButton() {
  function handleClick() {
    alert('You clicked me!');
  }

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );
}

5.2 class组件中的this问题

先来报错案例:

说明: JSX 回调函数中的 this,在 JavaScript 中,class 的方法默认不会绑定this

js 复制代码
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { message: 'hello' };
  }

  handleClick() {
    console.log(this) // 这里this为undefined
    this.setState({ message: '你好' })
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.message}</h2>
        <button onClick={this.handleClick}>点击事件</button>
      </div>
    );
  }
}

5.2.1 使用bind来解决this问题

为了在回调中使用 this,对this.handleClick.bind(this);这个绑定是必不可少的

js 复制代码
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { message: 'hello' };
	
    // 为了在回调中使用 `this`,这个绑定是必不可少的
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    console.log(this)
    this.setState({ message: '你好' })
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.message}</h2>
        <button onClick={this.handleClick}>点击事件</button>
      </div>
    );
  }
}

5.2.2 使用类字段来解决this问题(常用)

js 复制代码
class LoggingButton extends React.Component {
  // 此语法确保 `handleClick` 内的 `this` 已被绑定。
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

5.2.3 回调中使用箭头函数解决this问题

js 复制代码
class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    // 此语法确保 `handleClick` 内的 `this` 已被绑定。
    return (
      <button onClick={() => this.handleClick()}>
        Click me
      </button>
    );
  }
}

5.3 向事件处理程序传递参数

js 复制代码
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>

6. 条件渲染

6.1 if 语句进行条件渲染

js 复制代码
function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

6.2 与运算符 &&

js 复制代码
render() {
  const count = 0;
  return (
    <div>
      {count && <h1>Messages: {count}</h1>}
    </div>
  );
}

6.3 三目运算符

js 复制代码
render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
}

7. 列表 & Key

7.1 基础列表组件

使用 map 函数

js 复制代码
function NumberList() {
  const numbers = [1, 2, 3, 4, 5];
  return (
    <ul>
      {
        numbers.map(item => {
          return <li>{item}</li>
        })
      }
    </ul>
  )
}

7.2 key

应当给数组中的每一个元素赋予一个确定的标识

一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串,最好是用id

注意,最好不要用索引index作为key,有可能会导致一些问题

js 复制代码
function NumberList() {
  const numbers = [1, 2, 3, 4, 5];
  return (
    <ul>
      {
        numbers.map(item => {
          return <li key={item.toString()}>{item}</li>
        })
      }
    </ul>
  )
}

8. 表单

8.1 受控组件

渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做"受控组件"。

js 复制代码
class FormDemo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: '',
      textAreaValue: '',
      selectValue: '',
    }
  }

  handleNameChange = (e) => {
    this.setState({ value: e.target.value })
  }

  handleTextAreaChange = (e) => {
    this.setState({ textAreaValue: e.target.value })
  }

  handleSelectChange = (e) => {
    this.setState({ selectValue: e.target.value })
  }

  handleSubmit = () => {
    alert('提交的 input:' + this.state.value)
    alert('提交的 textarea:' + this.state.textAreaValue)
    alert('提交的 select:' + this.state.selectValue)
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          名字:
          <input value={this.state.value} onChange={this.handleNameChange}></input>
        </label>
        <br />

        <label>
          文章:
          <textarea value={this.state.textAreaValue} onChange={this.handleTextAreaChange} />
        </label>
        <br />

        <label>
          选择你喜欢的风味:
          <select value={this.state.selectValue} onChange={this.handleSelectChange}>
            <option value="grapefruit">葡萄柚</option>
            <option value="lime">酸橙</option>
            <option value="coconut">椰子</option>
            <option value="mango">芒果</option>
          </select>
        </label>
        <br />

        <input type="submit" value="提交" />
      </form>
    )
  }
}

8.2 处理多个输入

当需要处理多个 input 元素时,我们可以给每个元素添加 name 属性,并让处理函数根据 event.target.name 的值选择要执行的操作。

js 复制代码
class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          参与:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          来宾人数:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}

9. 状态提升

在 React 中,将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,便可实现共享 state。这就是所谓的"状态提升"

示例:

js 复制代码
// 子组件 A
class A extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  handleClick = () => {
    // 这里调用父组件传过来的方法进行修改父组件的state
    this.props.onGetAName('这是a传过来的')
  }

  render() {
    return (
      <div>
        <h3>这是A组件</h3>
        <button onClick={this.handleClick}>a按钮</button>
      </div>
    )
  }
}

// 子组件 B
class B extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  render() {
    return (
      <div>
        <h3>这是B组件,接收a的数据:{this.props.name}</h3>
      </div>
    )
  }
}

// 父组件
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      aName: ''
    };
  }

  getName = (val) => {
    this.setState({ aName: val })
  }

  render() {
    return (
      <div className="App">
        <A onGetAName={this.getName}></A>
        <B name={this.state.aName}></B>
      </div>
    )
  }
}

10. 组合 vs 继承

推荐使用组合而非继承来实现组件间的代码重用。

10.1 包含关系

组件使用一个特殊的 children prop 来将他们的子组件传递到渲染结果中:

js 复制代码
function FancyBorder(props) {
  return (
    <div className={'FancyBorder FancyBorder-' + props.color}>
      {props.children}
    </div>
  );
}

这使得别的组件可以通过 JSX 嵌套,将任意组件作为子组件传递给它们。

js 复制代码
function WelcomeDialog() {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        Welcome
      </h1>
      <p className="Dialog-message">
        Thank you for visiting our spacecraft!
      </p>
    </FancyBorder>
  );
}

11. 样式

11.1 行内样式

{} 中绑定一个style对象

js 复制代码
<h1 style={{ color: "red" }} onClick={this.click}>
  hello
</h1>

推荐:

js 复制代码
const style = {
  fontSize: "50px",
  color: 'red'
};

function App() {
  return (
    <div>
      <h1 style={style}>这是 App</h1>
      <Hello />
    </div>
  );
}

11.2 class 类名

  • 注意:这里绑定class要用 className
    .css
css 复制代码
.title {
    color: red;
}

App.js

js 复制代码
<h1 className="title" onClick={this.click}>
  hello
</h1>
相关推荐
沉默璇年5 分钟前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder11 分钟前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
2401_8827275720 分钟前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
会发光的猪。1 小时前
css使用弹性盒,让每个子元素平均等分父元素的4/1大小
前端·javascript·vue.js
天下代码客1 小时前
【vue】vue中.sync修饰符如何使用--详细代码对比
前端·javascript·vue.js
猫爪笔记1 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html
前端李易安2 小时前
Webpack 热更新(HMR)详解:原理与实现
前端·webpack·node.js
红绿鲤鱼2 小时前
React-自定义Hook与逻辑共享
前端·react.js·前端框架
Domain-zhuo2 小时前
什么是JavaScript原型链?
开发语言·前端·javascript·jvm·ecmascript·原型模式
小丁爱养花2 小时前
前端三剑客(三):JavaScript
开发语言·前端·javascript