美文网首页React
React系列教程(1)ReactJS快速入门

React系列教程(1)ReactJS快速入门

作者: __豆约翰__ | 来源:发表于2020-06-23 15:58 被阅读0次

    本教程配有免费视频教程

    视频教程地址

    豆约翰习惯将掌握某一技术分为5个层次:初窥门径,小试牛刀,渐入佳境,得心应手,玩转自如

    本篇属于React框架中的第1层次即初窥门径

    课程目标

    • 了解最常用的React概念和相关术语,例如JSX,组件,属性(Props),状态(state)。
    • 构建一个非常简单的React应用程序,以阐述上述概念。

    最终效果

    image

    创建React应用

    helloworld

    (1)安装node.js 官网链接

    (2)打开cmd 窗口 输入

    npm install --g create-react-app 
    npm install --g yarn
    

    (-g 代表全局安装)

    如果安装失败或较慢。需要换源,可以使用淘宝NPM镜像,设置方法为:npm config set registry https://registry.npm.taobao.org,设置完成后,

    重新执行

    cnpm install --g create-react-app
    cnpm install --g yarn
    

    安装 creat-react-app 功能组件,该组件可以用来初始化一个项目, 即 按照一定的目录结构,生成一个新项目

    (3)在你想创建项目的目录下 例如 D:/project/ 打开cmd命令 输入

    create-react-app react-tutorial
    

    去使用creat-react-app命令创建名字是react-tutorial的项目

    安装完成后,移至新创建的目录并启动项目

    cd react-tutorial
    yarn start
    

    一旦运行此命令,localhost:3000新的React应用程序将弹出一个新窗口。


    image

    项目目录结构

    一个/public和/src目录,以及node_modules,.gitignore,README.md,和package.json。


    image

    在目录/public中,重要文件是index.html,其中一行代码最重要

        <div id="root"></div>
    

    该div做为我们整个应用的挂载点

    /src目录将包含我们所有的React代码。

    要查看环境如何自动编译和更新您的React代码,请找到文件/src/App.js
    将其中的

            <a
              className="App-link"
              href="https://reactjs.org"
              target="_blank"
              rel="noopener noreferrer"
            >
              Learn React
            </a>
    

    修改为

            <a
              className="App-link"
              href="https://reactjs.org"
              target="_blank"
              rel="noopener noreferrer"
            >
              和豆约翰 Learn React
            </a>
    

    保存文件后,您会注意到localhost:3000编译并刷新了新数据。

    image
    现在删除/src目录中的所有文件,我们将从头开始创建自己的项目文件。

    开始我们的mini项目

    1.新建文件index.css
    我们就拷贝index.css文件的全部内容(css不是我们这次课程的重点).
    2.新建文件index.js
    在index.js中,我们将导入React,ReactDOM和CSS文件。
    src / index.js

    import React, { Component }  from 'react'
    import ReactDOM from 'react-dom'
    import './index.css'
    

    创建App组件,在render方法中返回一个div(这里是JSX语法)

    src / index.js

    class App extends Component {
      render() {
        return (
          <div className="App">
            <h1>Hello, React!</h1>
          </div>
        )
      }
    }
    

    最后,我们将App渲染到根节点。
    src / index.js

    ReactDOM.render(<App />, document.getElementById('root'))
    

    index.js完整代码

    import React, { Component }  from 'react'
    import ReactDOM from 'react-dom'
    import './index.css'
    
    
    class App extends Component {
        render() {
            return (
                <div className="App">
                    <h1>Hello, React!</h1>
                </div>
            )
        }
    }
    
    ReactDOM.render(<App />, document.getElementById('root'))
    
    

    在浏览器输入localhost:3000,您将看到“你好,React!


    image

    JSX:JavaScript + XML

    如您所见,我们在React代码中一直使用看起来像HTML的东西,但它并不是完全HTML。这是JSX,代表JavaScript XML。

    使用JSX,我们可以编写看起来像HTML的内容,也可以创建和使用我们自己的类似XML的标签。
    以下是JSX分配给变量的样子:

    const heading = <h1 className="site-heading">Hello, React</h1>
    

    编写React并非必须使用JSX。在幕后,它正在运行createElement,它接受标签,包含属性象和组件的后代,并呈现相同的信息。下面的代码将具有与上面的JSX相同的输出。

    const heading = React.createElement('h1', { className: 'site-heading' }, 'Hello, React!')
    

    JSX实际上更接近JavaScript,而不是HTML,因此在编写时需要注意一些关键区别。

    • className用于代替class添加CSS类(classJavaScript中的保留关键字)。
    • JSX中的属性和方法为camelCase(驼峰表示法) - onclick将变为onClick。
    • 自闭合标签必须以斜杠结尾-例如<img />
    • JavaScript表达式也可以使用大括号(包括变量,函数和属性)嵌入JSX内。
    const name = 'Tania'
    const heading = <h1>Hello, {name}</h1>
    

    JSX比在原生JavaScript中创建和添加元素更容易编写和理解,这也是人们如此热爱React的原因之一。

    组件

    到目前为止,我们已经创建了一个组件- App组件。React中的几乎所有内容都由组件组成,这些组件可以是类组件或简单组件。
    大多数React应用程序都有许多小组件,所有内容都加载到主App组件中。
    组件经常定义在单个js文件中,
    接下来让我们更改项目。从index.js中删除App类:
    index.js

    import React from 'react'
    import ReactDOM from 'react-dom'
    import App from './App'
    import './index.css'
    
    ReactDOM.render(<App />, document.getElementById('root'))
    

    我们将创建一个新文件App.js,并将组件放入其中。

    import React, { Component } from 'react'
    
    class App extends Component {
      render() {
        return (
          <div className="App">
            <h1>Hello, React!</h1>
          </div>
        )
      }
    }
    
    export default App
    

    我们将组件导出为App并将其加载到中index.js。将组件分成文件不是强制性的,但是如果不这样做的话,应用程序将开始变得笨拙和混乱。

    类组件

    让我们创建另一个组件。我们将创建一个表格。制作Table.js,并用以下数据填充。
    src / Table.js

    import React, { Component } from 'react'
    
    class Table extends Component {
      render() {
        return (
          <table>
            <thead>
              <tr>
                <th>Name</th>
                <th>Job</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td>Charlie</td>
                <td>Janitor</td>
              </tr>
              <tr>
                <td>Mac</td>
                <td>Bouncer</td>
              </tr>
              <tr>
                <td>Dee</td>
                <td>Aspiring actress</td>
              </tr>
              <tr>
                <td>Dennis</td>
                <td>Bartender</td>
              </tr>
            </tbody>
          </table>
        )
      }
    }
    
    export default Table
    

    我们创建的该组件是一个自定义类组件。自定义组件名称首字母大写,以区别于常规HTML元素。回到App.js,我们可以先将表格组件导入,以加载表格组件:
    src / App.js

    import Table from './Table'
    

    然后将其加载到App类的render()函数中,在此之前我们已经有了“ Hello,React!”。还更改了外部容器的类名。

    import React, { Component } from 'react'
    import Table from './Table'
    
    class App extends Component {
      render() {
        return (
          <div className="container">
            <Table />
          </div>
        )
      }
    }
    
    export default App
    
    image

    现在,我们已经了解了什么是自定义类组件。我们复用此组件。但是,由于数据已被硬编码到其中,因此目前它并不太有用。

    简单组件

    React中的另一种类型的组件是simple component,它是一个函数。该组件不使用class关键字。让我们为Table组件制作两个简单的子组件-一个表头和一个表主体。

    我们将使用ES6箭头表达式来创建这些简单的组件。首先,表头:
    src / Table.js

    const TableHeader = () => {
      return (
        <thead>
          <tr>
            <th>Name</th>
            <th>Job</th>
          </tr>
        </thead>
      )
    }
    

    然后是表主体。
    src / Table.js

    const TableBody = () => {
      return (
        <tbody>
          <tr>
            <td>Charlie</td>
            <td>Janitor</td>
          </tr>
          <tr>
            <td>Mac</td>
            <td>Bouncer</td>
          </tr>
          <tr>
            <td>Dee</td>
            <td>Aspiring actress</td>
          </tr>
          <tr>
            <td>Dennis</td>
            <td>Bartender</td>
          </tr>
        </tbody>
      )
    }
    

    现在,我们的Table.js文件将如下所示。请注意,TableHeader和TableBody组件都在同一个文件中,并由Table类组件使用。
    src / Table.js

    import React, { Component } from 'react'
    
    const TableHeader = () => {
        return (
            <thead>
            <tr>
                <th>Name</th>
                <th>Job</th>
            </tr>
            </thead>
        )
    }
    
    const TableBody = () => {
        return (
            <tbody>
            <tr>
                <td>Charlie</td>
                <td>Janitor</td>
            </tr>
            <tr>
                <td>Mac</td>
                <td>Bouncer</td>
            </tr>
            <tr>
                <td>Dee</td>
                <td>Aspiring actress</td>
            </tr>
            <tr>
                <td>Dennis</td>
                <td>Bartender</td>
            </tr>
            </tbody>
        )
    }
    
    
    class Table extends Component {
        render() {
            return (
                <table>
                    <TableHeader />
                    <TableBody />
                </table>
            )
        }
    }
    
    export default Table
    
    

    运行结果不变。如您所见,组件可以嵌套在其他组件中,并且简单和类组件可以混合使用。

    一个类组件必须包含render(),并且return只能返回一个父元素。

    作为总结,让我们比较一个简单的组件和一个类组件:.

    简单组件

    const SimpleComponent = () => {
      return <div>Example</div>
    }
    

    类组件

    class ClassComponent extends Component {
      render() {
        return <div>Example</div>
      }
    }
    

    props

    我们的Table组件,数据是硬编码的。关于React的重要问题之一是它如何处理数据,它使用属性(props)和状态(state)来处理数据。现在,我们将专注于使用props处理数据。

    首先,让我们从TableBody组件中删除所有数据。
    src / Table.js

    const TableBody = () => {
        return (
            <tbody></tbody>
        )
    }
    

    然后,将所有数据定义到一个对象数组中:
    src / App.js

    class App extends Component {
      render() {
        const characters = [
          {
            name: 'Charlie',
            job: 'Janitor',
          },
          {
            name: 'Mac',
            job: 'Bouncer',
          },
          {
            name: 'Dee',
            job: 'Aspring actress',
          },
          {
            name: 'Dennis',
            job: 'Bartender',
          },
        ]
    
        return (
          <div className="container">
            <Table />
          </div>
        )
      }
    }
    

    接下来,我们将通过属性characterData将数据传递给子组件Table,传递的数据是characters变量,由于它是JavaScript表达式,因此使用大括号括起来。

    return (
      <div className="container">
        <Table characterData={characters} />
      </div>
    )
    

    现在数据已经传递到Table组件,我们可以在Table组件通过this.props中访问到。
    src / Table.js

    class Table extends Component {
      render() {
        const { characterData } = this.props
    
        return (
          <table>
            <TableHeader />
            <TableBody characterData={characterData} />
          </table>
        )
      }
    }
    

    由于Table组件实际上由两个较小的简单组件组成,因此再次通过props 将其传递给子组件TableBody

    我们将把props作为参数传递给简单组件TableBody ,并通过数组的map方法将数据映射为jsx片段的集合。该jsx片段集合将包含在rows变量中,我们将其作为表达式返回。

    const TableBody = props => {
      const rows = props.characterData.map((row, index) => {
        return (
          <tr key={index}>
            <td>{row.name}</td>
            <td>{row.job}</td>
          </tr>
        )
      })
    
      return <tbody>{rows}</tbody>
    }
    

    您会注意到我已经向每个表行添加了一个键索引。在React中创建列表时,应始终使用,因为它们有助于识别每个列表项。我们还将在需要操纵列表项的时刻看到这是必要的。

    props是将现有数据传递到React组件的有效方法,但是该组件无法更改props-它们是只读的。在下一节中,我们将学习如何使用状态(state)来进一步控制React中的数据处理。

    state

    我们将表格数据存储在数组变量中,并将其作为props传递。但是如果我们希望能够从数组中删除一个项目,就做不到了。props,是一种单向数据流,子组件不能进行修改。但是有了state,我们就可以更新组件中的私有数据。

    您可以将state视为可以在组件内增删改的而不必添加到数据库的任何临时数据-例如,在确认购买之前在购物车中添加和删除的购物车项目。state改变后,绑定state数据的视图会自动更新。

    首先,我们将创建一个state对象。
    src / App.js

    class App extends Component {
      state = {}
    }
    

    在state对象中定义属性,保存我们所需的数据。
    src / App.js

    class App extends Component {
      state = {
        characters: [],
      }
    }
    

    将我们之前创建的对象的整个数组移到中state.characters。

    class App extends Component {
      state = {
       characters : [
                {
                    name: 'Charlie',
                    job: 'Janitor',
                },
                {
                    name: 'Mac',
                    job: 'Bouncer',
                },
                {
                    name: 'Dee',
                    job: 'Aspring actress',
                },
                {
                    name: 'Dennis',
                    job: 'Bartender',
                },
            ]
      }
    }
    

    在App.js中,创建removeCharacter方法来删除一个项目

    removeCharacter = index => {
      const { characters } = this.state
    
      this.setState({
        characters: characters.filter((character, i) => {
          return i !== index
        }),
      })
    }
    

    您必须使用this.setState()来修改数组。简单地将新值应用到this.state.property将不起作用。

    现在,我们必须将该函数传递给组件。我们会将removeCharacter函数作为属性传递给Table。
    src/App.js

    render() {
      const { characters } = this.state
    
      return (
        <div className="container">
          <Table characterData={characters} removeCharacter={this.removeCharacter} />
        </div>
      )
    }
    

    由于Table组件,并不需要自己的state数据对象,所以,我们将它改造成简单组件,并将removeCharacter函数继续向TableBody 子组件传递:
    src/Table.js

    const Table = props => {
      const { characterData, removeCharacter } = props
    
      return (
        <table>
          <TableHeader />
          <TableBody characterData={characterData} removeCharacter={removeCharacter} />
        </table>
      )
    }
    

    在TableBody组件中,我们将键/索引作为参数传递,因为removeCharacter函数知道要删除的项目索引。我们创建一个按钮并将其onClick事件绑定removeCharacter函数;
    src/Table.js

    <tr key={index}>
      <td>{row.name}</td>
      <td>{row.job}</td>
      <td>
        <button onClick={() => props.removeCharacter(index)}>Delete</button>
      </td>
    </tr>
    

    onClick事件必须绑定为返回该removeCharacter()方法的函数,否则removeCharacter()将尝试不等按钮点击而自动运行。

    image

    新增表格数据

    现在我们已经将数据存储在App.js组件的state对象中,并且可以从state对象中删除任何项目。但是,如何向state对象中添加数据呢?我们将通过一个表单组件来实现这个需求。

    首先,state.characters中删除所有硬编码数据:
    src / App.js

    class App extends Component {
      state = {
        characters: [],
      }
    }
    

    创建新文件Form.js。

    import React, { Component } from 'react'
    
    class Form extends Component {
      initialState = {
        name: '',
        job: '',
      }
    
      state = this.initialState
    }
    

    以前,React类组件有必要包括一个constructor(),但是现在不再需要。

    此表单的目标是Form每次更改表单中的字段时都会更新本组件(Form)的state,并且在我们提交表单时,所有数据都将传递给App组件的state,然后Table组件会自动更新。

    首先定义input控件的onChange事件处理函数:

    src / Form.js

    handleChange = event => {
      const { name, value } = event.target
    
      this.setState({
        [name]: value,
      })
    }
    

    Form组件的render函数实现如下:
    src / Form.js

    render() {
      const { name, job } = this.state;
    
      return (
        <form>
          <label htmlFor="name">Name</label>
          <input
            type="text"
            name="name"
            id="name"
            value={name}
            onChange={this.handleChange} />
          <label htmlFor="job">Job</label>
          <input
            type="text"
            name="job"
            id="job"
            value={job}
            onChange={this.handleChange} />
        </form>
      );
    }
    
    export default Form;
    

    在App.js,导入Form:

    import Form from './Form';
    
    return (
      <div className="container">
        <Table characterData={characters} removeCharacter={this.removeCharacter} />
        <Form />
      </div>
    )
    

    最后一步是实现提交该数据并更新父组件状态。我们将创建一个名为handleSubmit()的函数,该函数将使用[ES6扩展运算符]语法来更新状态。
    src / App.js

    handleSubmit = character => {
      this.setState({ characters: [...this.state.characters, character] })
    }
    

    确保我们将其作为参数传递给Form

    <Form handleSubmit={this.handleSubmit} />
    

    现在,在Form中,我们将创建一个名为submitForm()的方法,该方法将调用传进来的handleSubmit函数,并将Form的state作为character参数传递。它还将Form的state重置为初始状态,以在表单提交后清除表单信息。

    src / Form.js

    submitForm = () => {
      this.props.handleSubmit(this.state)
      this.setState(this.initialState)
    }
    

    最后,我们将在Form.js中添加一个提交按钮以提交表单,点击将调用我们刚定义的submitForm函数。
    src / Form.js

    <input type="button" value="Submit" onClick={this.submitForm} />
    

    就是这样!该应用程序已完成。

    image

    完整代码

    参考:
    https://www.taniarascia.com/getting-started-with-react/

    相关文章

      网友评论

        本文标题:React系列教程(1)ReactJS快速入门

        本文链接:https://www.haomeiwen.com/subject/lhtaahtx.html