初识React框架

106 阅读5分钟

第一次接触web React框架的一些记录,不过多追求完整与细节。

JSX

关于JSX的描述,React官网有一段描述:

It is called JSX, and it is a syntax extension to JavaScript. We recommend using it with React to describe what the UI should look like. JSX may remind you of a template language, but it comes with the full power of JavaScript.

JSX produces React “elements”. We will explore rendering them to the DOM in the next section. Below, you can find the basics of JSX necessary to get you started.

个人的理解是,JSX是一个在JS中为了方便绘制UI,操作DOM而出现一种"语法糖"。 React官网上的Hello world demo中,大致解释了JSX应该怎么用,以及React是如何执行渲染

<div id="root">
  <!-- This div's content will be managed by React. -->
</div>
function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};

const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>
);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<h1>Hello, world!</h1>);

Components

详情参考react-component.

Components

React 官网是这么介绍Components的:

React lets you define components as classes or functions. Components defined as classes currently provide more features which are described in detail on this page. To define a React component class, you need to extend React.Component

React官网举了两个最简单的例子:
函数

// 类似于c++中的普通函数
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// 类似于c++中的类的 operator() 运算符重载函数
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

个人理解为:components就是一个"组件",若从一个React的角度来看html,可以将这个html文件看作是由很多个不可再分的 components 而组成,而每一个components说到底其是就是一个在js中函数化的标签。同样的逻辑,也可以将很多个不可再分的components看作一个大的components

Attention: 在React的世界中,所有用户自定义的components必须以大写字母开头,这样做的目的是为了避免与html中的标签发生冲突。

Props

React官网对于Props的解释如下:

“props” (which stands for properties) object argument with data and returns a React element.

简单理解就是,props就是标签内的属性,例如:

const element = <div name="descosmos" width="713">

function GetProperty(props) {
    console.log("name: " + props.name + " width: " + props.width)
}
  • props在函数实现的自定义的components中,使用方法就是props.属性
  • props在类实现的自定义的components中,使用方法就是this.props.属性

React官网的demo代码:

<div id="root">
    <!-- This element's contents will be replaced with your component. -->
</div>
function Welcome(props) {  
    return <h1>Hello, {props.name}</h1>;
}

// function 的Welcome与类Welcome的作用其实一致

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

const root = ReactDOM.createRoot(document.getElementById('root'));
const element = <Welcome name="Sara" />;
root.render(element);

State

React 文档中对于components中的state的解释如下:

The state contains data specific to this component that may change over time. The state is user-defined, and it should be a plain JavaScript object.

If some value isn’t used for rendering or data flow (for example, a timer ID), you don’t have to put it in the state. Such values can be defined as fields on the component instance.

See State and Lifecycle for more information about the state.

Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.

简单来说,stateprops都是一个components实例中的实例化属性(instance-properties) , 只不过与props应用场景不一样的是,state作用在于保存components实例化后的instance唯一拥有的数据.

为了说明state的应用场景,React文档中给出了一个例子:输出当前时间.

const root = ReactDOM.createRoot(document.getElementById('root'));

class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

function tick() {
  root.render(<Clock date={new Date()} />);
}

setInterval(tick, 1000);

这份代码设置了一个定时器setInterval(tick, 1000);, tick将每一秒钟调用一次, 而tick函数每调用一次就执行一次渲染, root.render(<Clock date={new Date()} />); 相当于创建一个新的Clock components. 这样的调用方法显然不符合一般的认知, 因为Clock components 在第一次创建时已经存在, 后续只应该修改该components中的内容.

因此, 输出当前时间这个例子有了新的版本:

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

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

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

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

constructor,componentDidMount, componentWillUnmountrender都是一个components内置的方法,具体用法参考React文档. 这份代码与上面不同的地方在于:

  1. 这份代码只会创建一个Clock的components, 并在components初始化阶段调用constructor(props)初始state{date: new Date()}, 这一步类似于python中类的 __init__(self)函数;
  2. 在初始化结束之后, 会调用一次render进行渲染, 但此时的components 还没有插入到DOM中;
  3. 当components插入到DOM中时, 会调用componentDidMount为该components设置一个周期循环的行为, ;
  4. 之后在每一次设置的周期行为中, 只需调用this.setState修改state,setState函数内部对每一个状态的改变都会响应而调用render函数进行渲染.
  5. 当这个实例化的components被从DOM中移除时, 会自动调用componentWillUnmount, 这一步类似于c++中类的析构函数.

总而言之在React中, 对于每一个实例化components而言, 可以从外部获取数据, 也可以拥有自己的内部属性, 同时也可以提前定义自己的行为.

Handling Events

不同于一般处理响应需要在html中写明标签调用时间的handle一样, React的html文本因为是渲染出来的, 因此其对于事件handle的处理也不同:

  • html
    <button onclick="activateLasers()">
      Activate Lasers
    </button>
    
  • React
    <button onClick={activateLasers}>  
      Activate Lasers
    </button>
    

在React中, 对于响应的处理是类似于绑定一个callback, 不过从React文档中看其大致有三种绑定方式.

绑定方式

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

官方推荐使用这种绑定方式. 个人理解为, 在定义一个控件时, 必须要在该控件初始化阶段就定义谁来响应这个控件所带来的行为, 并且这种绑定方式可以保证, 一旦handle是一个类中的成员函数, 并且handle中调用了类的this指针, 这个this指针一定是有效的.

TODO

Reference

React installation