React学习之路(1): JSX&元素渲染&组件&props&state&生命周期

一、JSX

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

上面这种语法就是react中的JSX。按照官方文档的说法,这是为了使得渲染逻辑与UI逻辑内在耦合,所以React中采用将渲染逻辑与UI逻辑共同放在“组件”中来实现。其实就是在组件中共同操作了html与js,使得组件作为一个整体进行渲染(按照我的理解)。
JSX的语法也不止是像上面那样好像只是一个单纯的html节点,事实上,他也可以在JSX中嵌入表达式,甚至调用函数,如下

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

本身的JSX也是一个表达式,官方文档上说:在编译之后,JSX 表达式会被转为普通 JavaScript 函数调用,并且对其取值后得到 JavaScript 对象。也就是说可以将JSX赋值给变量、当作参数或者函数返回值
JSX支持对其中的属性值进行赋值,这里提供了两种方法,一种是使用引号,一种是使用大括号,这两种方式只能使用一种:

const element = <div tabIndex="0"></div>;
const element = <img src={user.avatarUrl}></img>;

React DOM 在渲染所有输入内容之前,默认会进行转义。它可以确保在你的应用中,永远不会注入那些并非自己明确编写的内容。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(cross-site-scripting, 跨站脚本)攻击。
JSX既可以使用上面类似html节点的写法,在babel中也可以使用React.createElement() 函数进行声明,两种形式是等价的。

二、元素渲染
React是创建开销极小的普通对象,通过ReactDOM来更新DOM节点来与React元素保持一致。
使用ReactDOM.render()可以将一个React元素渲染到根DOM节点中:

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

需要注意的是,一旦创建了React元素,它里面的子元素与属性是不可更改的,若要更新UI只能通过render函数重新渲染新的React元素,并且重新渲染的时候React会使用diff算法来将元素与之前状态进行比较,只更新必要的部分,减少渲染时间。

三、组件&Props
其实React与Vue有点像,都是提倡将UI分成可复用的组件来进行设计。这里介绍两种定义React组件的方法,两种方法是等效的:
1、函数组件

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

2、class组件

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

React元素可以是原生DOM标签,也可以是我们自定义的组件,若为自定义组件的话会将JSX接收的属性转换成props对象传给组件,例如:

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

这里其实相当于给Welcome组件传入了一个对象:

props:{
	name:"Sara"
}

React虽然灵活,但是它规定了组件不能修改自身的props,所以若想在组件中动态更新数据的话需要用到state。

四、State&生命周期
在官方文档中的一个计时器例子中,里面是通过每秒更新根DOM节点的React元素来实现每秒计时的,也就是说计时器的更新实际上是React元素的更新,而不是React元素内部数据的更新,state可以起到这个作用。

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>
    );
  }

1、先将props传入父类的构造函数中
2、在该类的构造函数中对state进行初始化
3、在render函数中使用this.state来获取组件中的数据
4、tick函数中使用setState来更新state的值

其中componentDidMount与componentWillUnmount是React中的生命周期钩子函数,有点类似Vue中的mount与beforeDestory,前者是在组件第一次被渲染到DOM中后,后者是组件将在DOM节点被删除之前。

需要注意的是,直接修改state中的值并不会使得组件重新渲染,所以一定要用setState来更新state。

官网中也提到state是异步更新的,贴出的例子如下:

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

这是一个错误的做法,按照我的理解:因为this.state.counter并不一定每次都是最新更新的state中的值,React可能处于性能考虑会将多个setState合并成一个setState来调用,所以造成state的更新其实是异步的。官方推荐的做法是将state作为参数传入setState函数中,这样的话每次调用的state都是上一次已经更新完成的,不能造成state异步的i情况,如下:

this.setState((state, props) => ({
  counter: state.counter + props.increment
}));

React的数据流动是向下的,即组件中的任何数据只属于自身,并且只能传递给文档树中低于他们的组件。

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值