React 基础

文章目录

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

React是什么?

用于构建用户界面的 JavaScript 库

1. JSX 简介

1.1 在 JSX 中嵌入表达式

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

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

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

1.2 JSX 中指定属性

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

const element = <img src={user.avatarUrl}></img>;

1.3 使用 JSX 指定子元素

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

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

1.4 JSX 表示对象

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

等效于:

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

2. 元素渲染

2.1 将一个元素渲染为 DOM

页面根节点

<div id="root">div>

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

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”)

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

3.1.2 class组件

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

3.2 渲染组件 & props

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

const element = <Welcome name="Sara" />;

子组件(children)例子:

<Welcome name="react">
  <span>children</span>
</Welcome>

最终props为

{name: 'react', children: {}}

3.1 Props的只读性

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

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

function sum(a, b) {
  return a + b;
}

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

function withdraw(account, amount) {
  account.total -= amount;
}

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

4. State & 生命周期

4.1 class 组件中的 state

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:方法会在组件卸载前调用

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

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

// 错误
this.state.comment = 'Hello';

而是应该使用 setState():

// 正确
this.setState({comment: 'Hello'});

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

4.3.2 State 的更新可能是异步的

出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。
因为 this.propsthis.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。
比如:

// 错误
this.setState({
  counter: this.state.counter + this.props.increment,
});

解决这个问题:
可以让 setState() 接收一个函数而不是一个对象

// 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 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

示例:

function MyButton() {
  function handleClick() {
    alert('You clicked me!');
  }

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

5.2 class组件中的this问题

先来报错案例:
说明: JSX 回调函数中的 this,在 JavaScript 中,class 的方法默认不会绑定this

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);这个绑定是必不可少的

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问题(常用)

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问题

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

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

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

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>

6. 条件渲染

6.1 if 语句进行条件渲染

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

6.2 与运算符 &&

render() {
  const count = 0;
  return (
    <div>
      {count && <h1>Messages: {count}</h1>}
    </div>
  );
}

6.3 三目运算符

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

7. 列表 & Key

7.1 基础列表组件

使用 map 函数

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,有可能会导致一些问题

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 以这种方式控制取值的表单输入元素就叫做“受控组件”。

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 的值选择要执行的操作。

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。这就是所谓的“状态提升”
示例:

// 子组件 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 来将他们的子组件传递到渲染结果中:

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

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

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对象

<h1 style={{ color: "red" }} onClick={this.click}>
  hello
</h1>

推荐:

const style = {
  fontSize: "50px",
  color: 'red'
};

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

11.2 class 类名

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

App.js

<h1 className="title" onClick={this.click}>
  hello
</h1>

你可能感兴趣的:(React,react.js,前端,前端框架)