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>
相关推荐
一ge科研小菜鸡8 分钟前
React前端框架:现代网页开发的基石(附带构建简单任务管理应用案例代码)
前端框架
熊的猫37 分钟前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
瑶琴AI前端1 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app
会发光的猪。1 小时前
如何在vscode中安装git详细新手教程
前端·ide·git·vscode
我要洋人死2 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人2 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人2 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR3 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香3 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596933 小时前
前端预览word、excel、ppt
前端·word·excel