import{_ as s,o as n,c as a,a as l}from"./app.ab8d0b9f.js";const p="/assets/react-life-cycle.67e890c0.png",b=JSON.parse('{"title":"React","description":"","frontmatter":{},"headers":[{"level":2,"title":"邂逅React","slug":"邂逅react","link":"#邂逅react","children":[{"level":3,"title":"React开发依赖","slug":"react开发依赖","link":"#react开发依赖","children":[]},{"level":3,"title":"Babel与React的关系","slug":"babel与react的关系","link":"#babel与react的关系","children":[]},{"level":3,"title":"React初体验","slug":"react初体验","link":"#react初体验","children":[]},{"level":3,"title":"第一个React程序","slug":"第一个react程序","link":"#第一个react程序","children":[]},{"level":3,"title":"组件化开发","slug":"组件化开发","link":"#组件化开发","children":[]},{"level":3,"title":"提前绑定this","slug":"提前绑定this","link":"#提前绑定this","children":[]},{"level":3,"title":"列表渲染","slug":"列表渲染","link":"#列表渲染","children":[]},{"level":3,"title":"计数器案例","slug":"计数器案例","link":"#计数器案例","children":[]}]},{"level":2,"title":"认识JSX语法","slug":"认识jsx语法","link":"#认识jsx语法","children":[{"level":3,"title":"JSX的使用","slug":"jsx的使用","link":"#jsx的使用","children":[]},{"level":3,"title":"JSX事件绑定","slug":"jsx事件绑定","link":"#jsx事件绑定","children":[]},{"level":3,"title":"事件绑定参数传递","slug":"事件绑定参数传递","link":"#事件绑定参数传递","children":[]},{"level":3,"title":"JSX事件绑定案例","slug":"jsx事件绑定案例","link":"#jsx事件绑定案例","children":[]},{"level":3,"title":"条件渲染","slug":"条件渲染","link":"#条件渲染","children":[]},{"level":3,"title":"列表渲染中的高阶函数","slug":"列表渲染中的高阶函数","link":"#列表渲染中的高阶函数","children":[]},{"level":3,"title":"JSX的本质","slug":"jsx的本质","link":"#jsx的本质","children":[]},{"level":3,"title":"声明式编程","slug":"声明式编程","link":"#声明式编程","children":[]},{"level":3,"title":"购物车案例","slug":"购物车案例","link":"#购物车案例","children":[]}]},{"level":2,"title":"React项目开发","slug":"react项目开发","link":"#react项目开发","children":[{"level":3,"title":"React脚手架","slug":"react脚手架","link":"#react脚手架","children":[]},{"level":3,"title":"React组件化开发","slug":"react组件化开发","link":"#react组件化开发","children":[]},{"level":3,"title":"类组件","slug":"类组件-1","link":"#类组件-1","children":[]},{"level":3,"title":"函数组件","slug":"函数组件","link":"#函数组件","children":[]},{"level":3,"title":"组件的生命周期","slug":"组件的生命周期","link":"#组件的生命周期","children":[]}]}],"relativePath":"note/React.md","lastUpdated":1681706359000}'),o={name:"note/React.md"},e=l(`

React

邂逅React

React开发依赖

为什么要拆分成这么多的包?

Babel与React的关系

Babel是什么?

二者之间的联系

React初体验

我们通过CDN方式引入react、react-dom、babel这三个依赖

并且创建#root根节点,作为渲染React组件的容器,再新建一个script标签,键入以下内容

html
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js" crossorigin></script>
<script type="text/babel">
  ReactDOM.render(<div>Hello, React!</div>, document.querySelector('#root'))
</script>

这时,一个内容为Hello, React!的div标签就被渲染到页面上了

需要注意的是:ReactDOM.render这种写法适用于React18之前,在React18之后建议用下面的代码渲染根节点:

tsx
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<h1>Hello, React!</h1>)

第一个React程序

设想我们现在有这样一个需求:点击按钮使文本Hello, World!变为Hello, React!

我们很容易就能写出如下代码:

tsx
const root = ReactDOM.createRoot(document.querySelector('#root'))
let msg = 'Hello, World!'

render() // initial render

function handleChangeClick() {
  msg = 'Hello, React!'
}

root.render(
  <div>
    <h1>{msg}</h1>
    <button onClick={handleChangeClick}>Change Text</button>
  </div>
)

在Vue中,如果我们对数据进行了修改,Vue的数据响应式会自动帮我们完成视图的更新

然而在React中,当我们修改了数据需要通知React,让React重新渲染视图。在这里,我们可以把渲染的过程封装为一个函数,方便我们重复调用,触发重新渲染

tsx
const root = ReactDOM.createRoot(document.querySelector('#root'))
let msg = 'Hello, World!'

render() // initial render

function handleChangeClick() {
  msg = 'Hello, React!'
  render() // re-render
}

function render() {
  root.render(
    <div>
      <h1>{msg}</h1>
      <button onClick={handleChangeClick}>Change Text</button>
    </div>
  )
}

这个案例中,我们使用{}语法,将动态的JS语法嵌入到JSX代码中

组件化开发

React有两种组件:类组件与函数组件,React18+推荐使用函数组件+Hooks

类组件

我们使用类组件来逐步重构上面的案例:

tsx
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      msg: 'Hello, World!'
    }
  }
  render() {
    return <h2>{this.state.msg}</h2>
  }
}

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)

:::success 需要注意的是,在constructor中我们调用了super,因为App类是继承自React.Component类,调用super即调用了其父类的构造函数,让我们的App组件可以继承一些内置属性/方法如state setState render :::

至此我们完成了数据的迁移,下面我们来完成事件函数的迁移。

有了之前的介绍,我们很容易的可以写出下面的代码:

tsx
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      msg: 'Hello, World!'
    }
  }
  changeText() {
    this.setState({
      msg: 'Hello, React!'
    })
  }
  render() {
    return (
      <div>
        <h2>{this.state.msg}</h2>
        <button onClick={this.changeText}>Change Text</button>
      </div>
    )
  }
}

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)

我们可以写一个实例方法changeText来修改msg,然而,此时我们点击按钮后发现,案例不能正常工作。

如果在changeText中打log,会发现函数被正常触发了,但是状态没有更新

为什么this.setState失效了?这和this的绑定有关:绑定的changeText在被调用时,向上找this找到的是全局的thisundefined

这种情况有点类似于下面的例子:

ts
const app = new App()
app.changeText() // this => app

const func = app.changeText
func() // this => undefined

在非严格模式下,直接调用func时的this指向的是window,严格模式下则为undefined

为了解决this绑定的问题,我们需要显式把函数调用绑定给当前组件,这时组件就可以正常工作了。

tsx
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      msg: 'Hello, World!'
    }
  }
  changeText() {
    this.setState({
      msg: 'Hello, React!'
    })
  }
  render() {
    return (
      <div>
        <h2>{this.state.msg}</h2>
        <button onClick={this.changeText.bind(this)}>Change Text</button>
      </div>
    )
  }
}

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)

提前绑定this

在render函数中频繁通过.bind毕竟不太优雅,好在也有另一种方式:可以在constructor中提前对实例方法进行this绑定:

tsx
...
constructor() {
  super()
  this.state = {
    msg: 'Hello, World!'
  }
  this.changeText = this.changeText.bind(this)
}
render() {
  ...
    <button onClick={this.changeText}>Change Text</button>
  ...
}
...

列表渲染

可以通过循环,将数组渲染到视图中

tsx
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      movieList: [
        'The Shawshank Redemption',
        'The Godfather',
        'The Godfather: Part II',
        'The Dark Knight'
      ]
    }
  }

  render() {
    return (
      <ul>
        {this.state.movieList.map((item) => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    )
  }
}

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)

需要注意的是,这里绑定的key的功能类似于Vue中的特殊属性key,它用来帮助React对列表渲染进行更高效的更新。

计数器案例

结合之前的知识,可以实现一个简单的计数器

tsx
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      count: 0
    }
    this.addCount = this.addCount.bind(this)
    this.subCount = this.subCount.bind(this)
  }

  addCount() {
    this.setState({
      count: this.state.count + 1
    })
  }

  subCount() {
    this.setState({
      count: this.state.count - 1
    })
  }

  render() {
    const { count } = this.state

    return (
      <div>
        <h1>Count: {count}</h1>
        <button onClick={this.addCount}>Add</button>
        <button onClick={this.subCount}>Sub</button>
      </div>
    )
  }
}

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)

认识JSX语法

是因为我们给script标签添加了type="text/babel"属性,浏览器不会对这个script进行解析,当babel被加载完成后,babel会在页面中寻找type="text/babel"的script标签进行转义,转义后的代码才会被浏览器执行

JSX的使用

书写JSX的规范与注意事项

JSX的注释

在JSX中编写注释,需要以{/* ... */}的形式,在.jsx/.tsx文件中,通过快捷键就可以快捷的生成注释内容

本质上是通过花括号语法{}嵌入了一段JavaScript表达式,在表达式中书写注释

tsx
...
return (
  <div>
    {/* Some Comment... */}
    <h1>Count: {count}</h1>
    <button onClick={this.addCount}>Add</button>
    <button onClick={this.subCount}>Sub</button>
  </div>
)
...

JSX嵌入变量作为子元素

可以通过花括号语法将变量内容嵌入到JSX语法中:

tsx
const message = 'Hello, React!'
const arr = ['abc', 'cba', 'nba']

return (
  <div>
    <h1>{ message }</h1>
    <div>{ arr }</div>
  </div>
)

下例中,只有number类型会被正常展示,而其余变量则不会展示在视图中

tsx
render() {
  const number = 123
  const n = null
  const u = undefined
  const b = true

  return (
    <div>
      <div>
        Number: {number}
      </div>
      <div>
        Null: {n}
      </div>
      <div>
        Undefined: {u}
      </div>
      <div>
        Boolean: {b}
      </div>
    </div>
  )
}

将对象类型变量嵌入到JSX语法中,React会抛出错误:

tsx
...
render() {
  const obj = { name: 'Ziu' }
  return (
    <div>
      { obj }
    </div>
  )
}
...

JSX的属性绑定

下例中,我们通过花括号语法对元素的属性进行了动态绑定,点击按钮可以切换className状态

同时,动态绑定的内联样式也会发生改变,通过花括号语法动态绑定style属性

tsx
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      isActive: false,
      title: 'Description'
    }
    this.changeActive = this.changeActive.bind(this)
  }

  changeActive() {
    this.setState({
      isActive: !this.state.isActive
    })
  }

  render() {
    const { isActive, title } = this.state
    const classList = ['title', isActive ? 'active' : '']

    return (
      <div>
        <div
          className={classList.join(' ')}
          title={title}
          style={{ color: isActive ? 'red' : 'blue' }}
        >
          Hello, React!
        </div>
        <button onClick={this.changeActive}>Change Active</button>
      </div>
    )
  }
}

当我们通过脚手架创建项目时,可以使用第三方库来帮我们完成className的绑定

JSX事件绑定

先前的例子中,我们已经通过onClick给按钮绑定过事件处理函数了,其中涉及了this绑定

回顾一下this的四种绑定规则:

  1. 默认绑定 独立执行 foo() this => undefined
  2. 隐式绑定 被一个对象执行 obj.foo() this => obj
  3. 显式绑定 call/bind/apply foo.call('aaa') this => String('aaa')
  4. new绑定 new Foo() 创建一个新对象,并且赋值给this

除了之前通过function + bind绑定事件处理函数的方式,还可以通过箭头函数来帮我们完成处理

箭头函数的内部使用this时会自动向上层作用域查找this 实际开发中这种方式并不常用

tsx
...
changeActive = () => {
  this.setState({
    isActive: !this.state.isActive
  })
}
...

相比之下更推荐使用的,是下面这种方式:

tsx
...
<button onClick={() => this.changeActive()}>Change Active</button>
...

这样书写有几种好处:

它的原理是,我们对外暴露的本质上是一个箭头函数,当调用箭头函数时,本质上是执行this.changeActive,这是 一种隐式绑定,找到的this为当前组件实例

事件绑定参数传递

事件回调函数的第一个默认参数就是Event对象,这个Event对象是经过React包装后的,但是原生的属性都包含在内,React对其进行了一些扩展

tsx
...
changeActive(ev) {
  console.log('Event', ev)
}

render() {
  return (
    <div>
      {/* event将作为默认入参传递给changeActive */}
      <button onClick={this.changeActive}>Change Active</button>

      {/* 通过箭头函数绑定事件监听回调函数时 需要手动透传一下event */}
      <button onClick={(ev) => this.changeActive(ev)}>Change Active</button>
    </div>
  )
}
...

当我们需要传递额外的参数时,通过箭头函数传递也更容易:

tsx
changeActive(ev, name, age) {
  console.log('Event', ev)
  console.log('Name', name)
  console.log('Age', age)
}

render() {
  return (
    <div>
      {/* NOT Recommand */}
      <button onClick={this.changeActive.bind(this, 'Ziu', 18)}>Change Active</button>
      {/* Recommand */}
      <button onClick={(ev) => this.changeActive(ev, 'Ziu', 18)}>Change Active</button>
    </div>
  )
}

需要注意,当通过.bind传递额外参数时,最后一个参数才是默认传递的Event对象,这会导致非预期行为

sh
> Event 'Ziu'
> Name 18
> Age {Event}

JSX事件绑定案例

创建一个Tab栏,选中哪个选项,哪个选项被激活切换为红色,同一时间仅有一个激活项目

结合之前学习的内容,很容易就可以写出下述 代码:

tsx
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      activeIndex: 0,
      tabList: ['Home', 'Recommend', 'Hot', 'User']
    }
  }

  changeActive(index) {
    this.setState({
      activeIndex: index
    })
  }

  render() {
    const { activeIndex, tabList } = this.state

    return (
      <div>
        <div className="tabs">
          {tabList.map((item, index) => (
            <button
              className={'tab ' + index === activeIndex ? 'active' : ''}
              style={{
                color: index === activeIndex ? 'red' : 'black'
              }}
              key={index}
              onClick={() => this.changeActive(index)}
            >
              {item}
            </button>
          ))}
        </div>
      </div>
    )
  }
}

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)

条件渲染

控制元素按照某种条件渲染,以加载状态为例

列表未加载出来时,展示加载中,加载完毕则渲染完整内容:

tsx
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      isLoading: true
    }
  }

  changeLoading() {
    this.setState({
      isLoading: !this.state.isLoading
    })
  }

  render() {
    const { isLoading } = this.state

    return (
      <div>
        {isLoading ? (
          <div className="loading"> Loading ... </div>
        ) : (
          <div className="list">Some Content</div>
        )}
        <button onClick={() => this.changeLoading()}>Toggle Loading</button>
      </div>
    )
  }
}

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)

常用的条件渲染方式

下例中通过逻辑与运算符&&决定VIP标签是否展示在视图中

tsx
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      isVip: false
    }
  }

  changeVip() {
    this.setState({
      isVip: !this.state.isVip
    })
  }

  render() {
    const { isVip } = this.state

    return (
      <div>
        <div class="user">
          <span>username: Ziu</span>
          {isVip && <span className="vip-banner"> VIP </span>}
        </div>

        <button onClick={() => this.changeVip()}>Toggle Vip</button>
      </div>
    )
  }
}

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)

在React中简单写一个"v-show"

v-show是Vue提供的语法糖,不同于v-if,它只切换元素的display属性。

下面我们在React中简单复现一个v-show的效果:

tsx
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      isShow: true
    }
  }

  changeShow() {
    this.setState({
      isShow: !this.state.isShow
    })
  }

  render() {
    const { isShow } = this.state

    return (
      <div>
        <div style={{ display: isShow ? '' : 'none' }}>Target Element</div>
        <button onClick={() => this.changeShow()}>Toggle Show</button>
      </div>
    )
  }
}

实际使用中,将其封装为hooks来调用更具通用性,也更方便管理

列表渲染中的高阶函数

tsx
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      stuList: [
        { name: 'Ziu', age: 18, score: 88 },
        { name: 'Kobe', age: 19, score: 59 },
        { name: 'Why', age: 20, score: 61 },
        { name: 'James', age: 21, score: 99 }
      ]
    }
  }

  render() {
    const { stuList } = this.state

    // 及格的学生
    const passStuList = stuList.filter((item) => item.score >= 60)

    // 分数最高的两个学生
    const top2StuList = stuList.sort((a, b) => b.score - a.score).slice(0, 2)

    return (
      <div>
        <div className="list">
          {stuList.map(({ name, age, score }) => (
            <div className="item" key={name}>
              <span className="name">{name}</span>
              <span className="age">{age}</span>
              <span className="score">{score}</span>
            </div>
          ))}
        </div>
      </div>
    )
  }
}

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)

JSX的本质

JSX的转换过程

假设我们有下面的JSX代码:

tsx
class App extends React.Component {
  constructor() {
    super()
  }

  render() {
    const page = (
      <div className="page">
        <div className="header">Header</div>
        <div className="content">
          Content
          <div className="banner">Banner</div>
          <ul>
            <li>Item 1</li>
            <li>Item 2</li>
            <li>Item 3</li>
            <li>Item 4</li>
            <li>Item 5</li>
          </ul>
        </div>
        <div className="footer">Footer</div>
      </div>
    )
    console.log(page)
    return <div>{page}</div>
  }
}

通过JSX语法描述出来的template会经过Babel转化,转化为JavaScript树的数据结构

在控制台中我们可以看到,子节点都存放进了父节点的props.children

虚拟DOM树

JSX仅仅是React.createElement(component, props, ...children)的语法糖

所有的JSX语法都会被Babel转化为这样的命令式语法

.createElement函数的参数

我们借助Babel官网的Playground来检查一下JSX语法的转化

js
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
const page = /*#__PURE__*/_jsxs("div", {
  className: "page",
  children: [/*#__PURE__*/_jsx("div", {
    className: "header",
    children: "Header"
  }), /*#__PURE__*/_jsxs("div", {
    className: "content",
    children: ["Content", /*#__PURE__*/_jsx("div", {
      className: "banner",
      children: "Banner"
    }), /*#__PURE__*/_jsxs("ul", {
      children: [/*#__PURE__*/_jsx("li", {
        children: "Item 1"
      }), /*#__PURE__*/_jsx("li", {
        children: "Item 2"
      }), /*#__PURE__*/_jsx("li", {
        children: "Item 3"
      }), /*#__PURE__*/_jsx("li", {
        children: "Item 4"
      }), /*#__PURE__*/_jsx("li", {
        children: "Item 5"
      })]
    })]
  }), /*#__PURE__*/_jsx("div", {
    className: "footer",
    children: "Footer"
  })]
});
console.log(page);

这时经过Babel转义后的纯JS函数,这段函数可以在浏览器中直接运行

如果移除了相关JSX代码,并将他们都替换为React.createElement函数调用,那么得到的代码也可以直接在浏览器中运行。Babel帮助我们完成了转化,提高了开发效率,相比于通过调用React.createElement来描述视图,通过JSX编写的代码更加容易维护

这些代码最终形成的就是虚拟DOM树,React可以将虚拟DOM渲染到页面上,形成真实DOM

虚拟DOM允许React可以通过diff算法,高效地对真实DOM树进行更新

声明式编程

购物车案例

下面写一个经典的购物车案例

tsx
function formatPrice(price) {
  return \`$ \${price.toFixed(2)}\`
}

class App extends React.Component {
  constructor() {
    super()
    this.state = {
      books: [
        { name: 'book1', author: 'author1', price: 100, count: 0 },
        { name: 'book2', author: 'author2', price: 200, count: 0 },
        { name: 'book3', author: 'author3', price: 300, count: 0 },
        { name: 'book4', author: 'author4', price: 400, count: 0 }
      ]
    }
  }

  changeCount(index, count) {
    this.setState((state) => {
      const books = [...state.books]
      books[index].count += count
      return { books }
    })
  }

  removeItem(index) {
    this.setState((state) => {
      const books = [...state.books]
      books.splice(index, 1)
      return { books }
    })
  }

  getTotal() {
    const { books } = this.state
    return books.reduce((acc, { price, count }) => acc + price * count, 0)
  }

  renderBookCart() {
    const { books } = this.state
    const total = this.getTotal()
    return (
      <div className="shopping-cart">
        <h1>Shopping Cart</h1>
        <div className="books">
          {books.map(({ name, author, price, count }, index) => (
            <div className="book" key={name}>
              <span className="idx">{index + 1}</span>
              <span className="name">{name}</span>
              <span className="author">{author}</span>
              <span className="price">{formatPrice(price)}</span>
              <span className="counter">
                <button onClick={() => this.changeCount(index, -1)} disabled={count <= 0}>
                  -
                </button>
                <span className="counter-number">{count}</span>
                <button onClick={() => this.changeCount(index, 1)}>+</button>
              </span>
              <button onClick={() => this.removeItem(index)}>Delete</button>
            </div>
          ))}
        </div>
        <div className="total">
          <span>Total: {formatPrice(total)}</span>
        </div>
      </div>
    )
  }

  renderEmptyTip() {
    return <div className="empty">Shopping Cart is Empty</div>
  }

  render() {
    const isEmpty = this.state.books.length === 0

    return !isEmpty ? this.renderBookCart() : this.renderEmptyTip()
  }
}

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)

React项目开发

React脚手架

类似于Vue提供的 pnpm create vite 创建一个模板,React也可以通过 create-react-app 来初始化一个空的React模板

sh
pnpm add create-react-app -g # 全局安装create-react-app
create-react-app react-app # 创建一个名为react-app的React项目
# 删除node_modules package-lock.json
cd react-app
pnpm i # 使用pnpm重新安装依赖
tsx
// index.js
import ReactDOM from 'react-dom/client'
import App from './App'

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)

// App.jsx
import { Component } from 'react'

export default class App extends Component {
  render() {
    return <div>Hello, React!</div>
  }
}

React组件化开发

组件化是React的核心思想之一,组件化是一个抽象的过程,将大的应用程序抽象为多个小的组件,最终形成组件树

分而治之,让代码更容易组织和管理

React组件相对于Vue更加灵活多样,按照不同的方式可以分为多种组件

除此之外,还有异步组件、高阶组件等...

类组件

render函数

被调用时组件内会检查this.propsthis.state是否发生变化,并且返回下面的返回值之一:

函数组件

函数组件不需要继承自任何父类,函数的返回值相当于render函数的返回值,表示组件要渲染的内容

修改前文中编写的App.jsx即可:

tsx
// App.jsx
export default function App() {
  return <div>Hello, React!</div>
}

组件的生命周期

我们需要在组件的不同生命周期中执行不同的操作,比如添加解除监听器、发起网络请求等

React Life Cycle: https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

',170),c=[e];function t(r,F,D,y,i,C){return n(),a("div",null,c)}const u=s(o,[["render",t]]);export{b as __pageData,u as default};