react入门记录

315 阅读7分钟

一、基础入门体验

1、初体验

执行安装命令,主要包括react和react-dom两个包。 npm install react react-dom

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="root"></div>

    <!-- 1.引入js文件 -->
    <script src="./node_modules/react/umd/react.development.js"></script>
    <script src="./node_modules/react-dom/umd/react-dom.development.js"></script>

    <script>
        // 2 创建react元素
        // 参数1:标签
        // 参数2:属性
        // 参数3及以后的参数:子节点
        const title = React.createElement('h1', null, 'hello React')

        // 3 渲染页面
        // 参数1:react元素
        // 参数2:容器挂载点
        ReactDOM.render(title, document.querySelector('#root'))
    </script>
</body>
</html>

2、raect脚手架

执行命令

npx create-react-app <项目名>

image.png

// 1 引入包
import React from 'react'
import ReactDOM from 'react-dom'

// 2 创建react元素
const title = React.createElement('h1', null, 'hello react 脚手架!!')

// 3 渲染react元素
ReactDOM.render(title, document.getElementById('root'))

3、JSX初体验

  • 3.1 createElement()的问题
    • 繁琐不简洁,不够优雅
    • 不够直观,很难一言识别出所描述的结构
  • 3.2 JSX
    • JSX是JavaScript XML的简写,表示在javascript代码中书写XML(HTML)格式的代码
    • 优势:声明式语法更加直观,与HTML结构相同,降低了学习成本、提高了开发效率
  • 3.3 注意点
    • React元素的属性名使用驼峰命名法
    • 特殊属性名:class->className、for->htmlFor、tabindex->tabIndex
    • 没有子节点的React元素可以用/>结束
    • 建议:使用小括号包裹JSX,从而避免JS中的自动插入分好陷阱
import React from 'react'
import ReactDOM from 'react-dom'

// 1 创建react元素
const title = (
  <h1 className="title">
    hello JSX
    <span />
  </h1>
)

// 2 渲染react元素
ReactDOM.render(title, document.getElementById('root'))

4、在JSX中使用javascript表达式

语法:{ javascript表达式 }

import React from 'react'
import ReactDOM from 'react-dom'

const name = 'yusong'
const age = 26
const title = (
  <h1>
    my name is 
    <span> { name }</span> 
    <span> age:{ age }</span> 
  </h1>
)

ReactDOM.render(title, document.getElementById('root'))

5、JSX条件渲染

条件渲染:根据条件渲染特定的JSX结构

可以使用if-else或者三元表达式或者逻辑与运算符来实现

import React from 'react'
import ReactDOM from 'react-dom'

const isLoading = true

// 1、if-else
const loadData = () => {
  if (isLoading) {
    return <div>加载中。。。</div>
  }

  return <div>加载完毕!</div>
}

// 2、三元表达式
const loadData1 = () => {
  return isLoading ? (<div>加载中1。。。</div>) : (<div>加载完毕1!</div>)
}

// 3、逻辑与运算符
const loadData2 = () => {
  return isLoading && (<div>加载中2。。。</div>)
}

const title = (
  <h1>
    {loadData()}
    {loadData1()}
    {loadData2()}
  </h1>
)

ReactDOM.render(title, document.getElementById('root')) 

6、JSX列表渲染

  • 如果要渲染一组数据,应该使用数组的map()方法
  • 注意:渲染列表时应该添加key属性,key的值要确保唯一性
  • 原则:map()遍历谁,就给谁添加key属性
  • 注意:与vue一样,尽量避免使用索引值作为key
import React from 'react'
import ReactDOM from 'react-dom'

const songs = [
  {id: 1, name: '奇迹再现'},
  {id: 2, name: '不见就'},
  {id: 3, name: '好不容易'}
]

const list = (
  <ul>
    {songs.map(item => <li key={item.id}>{item.name}</li>)}
  </ul>
)

ReactDOM.render(list, document.getElementById('root'))

7、JSX的样式处理

  • 行内样式(style)
// 注意不是vue中的双大括号,是一个对象
<h1 style={{fontSize: '20px', color: 'red', backgroundColor: 'skyblue'}}>
    style
</h1>
  • 类名(className(推荐))
<h1 className="title">
    style
</h1>

8、小结

  • React完全使用js语言本身的能力来编写UI,而不是通过造轮子的方式来增强HTML能力。

二、 React组件

1、组件的介绍

  • 特点:可复用、独立、可组合

2、组件的两种创建方式

使用函数创建组件

  • 函数组件:使用JS函数(或者箭头函数)创建的组件
  • 为了和普通函数做区分,react的函数组件做了以下约定
    • 约定1:函数名称必须以大写字母开头
    • 约定2:组件名称必须以大写字母开头,React以此来区分组件和普通的React元素
    • 约定3:函数组件必须有返回值,表示该组件的结构。如果返回值为null,则表示不渲染内容
  • 渲染函数组件:用定义的函数名称直接作为组件的标签名称即可
    • 组件标签既可以是单标签也可以是双标签
// 函数组件
// function SayHi() {
//     return (
//         <div>hi,function component</div>
//     )
// }

// 箭头函数
const SayHi = () => <div>hi,箭头函数</div>

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

使用类创建组件

  • 类组件:使用ES6的class创建的组件
  • 为了和普通的类做区分,react对类组件做了以下约定
    • 约定1:类名称必须以大写字母开头
    • 约定2:类组件必须继承React.component父类
    • 约定3:类组件必须提供render()方法
    • 约定4:render()方法必须有返回值,返回值表示该组件的结构
// 类组件
class SayHi extends React.Component {
    render() {
        return (
            <div>hi, class component</div>
        )
    }
}

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

抽离为独立的JS文件

  1. 创建HelloWorld.js
  2. 在HelloWord.js中导入React
  3. 创建组件(函数或者类)
  4. 在HelloWorld.js组件中导出该组件
  5. 在index.js中导入HelloWorld组件
  6. 渲染组件
// HelloWorld.js
import React from 'react'

class HelloWorld extends React.Component {
    render() {
        return (
            <div>hello, world</div>
        )
    }
}
// 导出
export default HelloWorld


// index.js
// 导入
import HelloWorld from './HelloWorld'
// 渲染
ReactDOM.render(<HelloWorld />, document.getElementById('root'))

3、React事件处理

事件绑定

  • React事件绑定语法与DOM事件绑定语法相似
  • 语法:on+时间名称={事件处理程序},比如:onClick={() => {}}
  • 注意点:React事件采用驼峰命名法,比如:onMouseEnter,onKeyUp
// 类组件
class App extends React.Component {
    handleClick() {
        console.log('单击事件触发了')
    }
    render() {
        return (
            <button onClick={this.handleClick}>click</button>
        )
    }
}

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

// 函数组件
function FunctionComponent() {
    function handleClick() {
        console.log('funciton component click trigger');
    }

    return (
        // 不需要this
        <button onClick={handleClick}>click function component</button>
    )
}

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

事件对象

  • 可以通过事件处理程序的参数获取事件对象
  • React中的事件对象叫做:合成事件对象
  • 合成事件:兼容所有浏览器,react内部帮我们封装处理了兼容性问题
class App extends React.Component {
    handleClick(e) {
        console.log('单击事件触发了')
        // 阻止事件默认行为
        e.preventDefault()
    }
    render() {
        return (
            <a href="https://www.baidu.com/" onClick={this.handleClick}>click</a>
        )
    }
}

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

4、有状态组件和无状态组件

  • 函数组件又叫做无状态组件,类组件又叫做有状态组件
  • 状态(state)即数据
  • 函数组件没有自己的状态,只负责数据的展示(静态)
  • 类组件有自己的状态,负责更新UI,让页面动起来

5、组件中的state和setState()

state的基本使用

  • 状态(state)即数据,是组件内部的私有数据,只能在组件内部使用
  • state的值是对象,表示一个组件中可以有多个数据
  • 通过this.state来获取状态
class App extends React.Component {
    constructor() {
        super()
        // 初始化状态
        this.state = {
            count: 0
        }
    }

    // 简化语法初始化state
    // state = {
    //     count: 10
    // }

    render() {
        return (
            <div>state: { this.state.count }</div>
        )
    }
}

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

setState()修改状态

  • 语法:this.setState({需要修改的数据})
  • 注意:不要直接通过this.state的值来修改数据
  • setState()的作用
    • 修改state数据
    • 更新UI
    • 通过数据驱动视图
class App extends React.Component {
    constructor() {
        super()
        // 初始化状态
        this.state = {
            count: 0
        }
    }

    // 简化语法初始化state
    // state = {
    //     count: 10
    // }

    render() {
        return (
            <div>
                <div>state: { this.state.count }</div>
                {/* 点击事件 */}
                <button onClick={() => {
                    this.setState({
                        count: this.state.count + 1
                    })
                }}>+1</button>
            </div>
        )
    }
}

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

6、事件绑定this指向

箭头函数

利用箭头函数自身不绑定this的特点

class App extends React.Component {
    constructor() {
        super()
        // 初始化状态
        this.state = {
            count: 0
        }
    }

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

    render() {
        return (
            <div>
                <div>state: { this.state.count }</div>
                {/* 用箭头函数包裹,箭头函数中的this指向外部环境,此处为render()的this指向 */}
                <button onClick={() => { this.handleClick() }}>+1</button>
            </div>
        )
    }
}

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

Function.prototype.bind()

通过ES5中的bind方法,将事件处理程序中的this与组件实例绑定到一起

class App extends React.Component {
    constructor() {
        super()
        // 这里通过bind()处理一下
        this.handleClick = this.handleClick.bind(this)
        // 初始化状态
        this.state = {
            count: 0
        }
    }

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

    render() {
        return (
            <div>
                <div>state: { this.state.count }</div>
                <button onClick={ this.handleClick }>+1</button>
            </div>
        )
    }
}

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

class的实例方法

  • 利用箭头函数形式的class实例方法

class App extends React.Component {
    constructor() {
        super()
        // 初始化状态
        this.state = {
            count: 0
        }
    }

    // 定义为箭头函数
    handleClick = () => {
        this.setState({
            count: this.state.count + 1
        })
    }

    render() {
        return (
            <div>
                <div>state: { this.state.count }</div>
                <button onClick={ this.handleClick }>+1</button>
            </div>
        )
    }
}

7、表单处理

受控组件

  • 定义:其值受到了React控制的表单元素
  • HTML中的表单元素是可输入的,也就是有自己的可变状态
  • React中的可变状态通常保存在state中,并且只能通过setState()来修改
  • React将state与表单表单元素值value绑定到一起,由state的值来控制表单元素的值
<input type="text" value={this.state.txt} />

使用步骤

  • 在state中添加一个状态,作为表单元素的value值(控制表单元素值的来源)
  • 给表单元素绑定change事件,将表单元素的值设置为state的值(控制表单元素的值的变化)
class App extends React.Component {
    constructor() {
        super()
        // 初始化状态
        this.state = {
            txt: '',
            content: '',
            selectCont: 'sz',
            isChecked: false
        }
    }

    // 处理文本框的change
    handleChange = e => {
        this.setState({
            txt: e.target.value
        })
    }

    // 处理文本域的change
    handleContent = e => {
        this.setState({
            content: e.target.value
        })
    }


    // 处理下拉框的change
    handleSelectChange = e => {
        this.setState({
            selectCont: e.target.value
        })
    }

    // 处理复选框的change
    handleCheckChange = e => {
        this.setState({
            isChecked: e.target.checked
        })
    }

    render() {
        return (
            <div>
                {/* 文本框 */}
                <input type="text" value={this.state.txt} onChange={this.handleChange} />
                <br />

                {/* 文本域 */}
                <textarea value={this.state.content} onChange={this.handleContent}></textarea>
                <br />

                {/* 下拉框 */}
                <select value={this.state.selectCont} onChange={this.handleSelectChange}>
                    <option value="zs">深圳</option>
                    <option value="gz">广州</option>
                    <option value="dg">东莞</option>
                </select>
                <br />

                {/* 复选框 */}
                <input type="checkbox" checked={this.state.isChecked} onChange={this.handleCheckChange}></input>
            </div>
        )
    }
}
  • 代码优化
    • 给表单元素添加name属性,名称与state相同,以此来实现动态修改state的不同字段
    • 根据表单元素获取对应的值,比如checkbox是checked属性
    • 在change方法中,通过[name]来实现动态修改state的不同字段
class App extends React.Component {
    constructor() {
        super()
        // 初始化状态
        this.state = {
            txt: '',
            content: '',
            selectCont: 'sz',
            isChecked: false
        }
    }

    // 处理文本域的change
    handleChange = e => {
        const target = e.target
        // 获取name属性
        const name = target.name
        // 判断是否为checkbox
        const value = target.type === 'checkbox'
            ? target.checked
            : target.value
        this.setState({
            [name]: value
        })
    }

    render() {
        return (
            <div>
                {/* 文本框 */}
                <input type="text" name="txt" value={this.state.txt} onChange={this.handleChange} />
                <br />

                {/* 文本域 */}
                <textarea name="content" value={this.state.content} onChange={this.handleChange}></textarea>
                <br />

                {/* 下拉框 */}
                <select name="selectCont" value={this.state.selectCont} onChange={this.handleChange}>
                    <option value="zs">深圳</option>
                    <option value="gz">广州</option>
                    <option value="dg">东莞</option>
                </select>
                <br />

                {/* 复选框 */}
                <input type="checkbox" name="isChecked" checked={this.state.isChecked} onChange={this.handleChange}></input>
            </div>
        )
    }
}

非受控组件(DOM方式)

  • 借助ref,使用原生DOM方式来获取表单元素值
  • ref的作用基本与vue中的ref一样(使用方法不一样):获取DOM或者组件
  • 使用步骤:
    • 调用React.createRef()方法创建一个ref对象
    • 将创建好的ref对象绑定到DOM元素或者组件上
    • 通过ref对象获取对应的值
class App extends React.Component {
    constructor() {
        super()

        // 调用React.createRef()方法创建一个ref对象
        this.txtRef = React.createRef()
    }

    getValue = () => {
        // 通过ref对象获取对应的值
        console.log(this.txtRef.current.value)
    }

    render() {
        return (
            <div>
                {/* 将创建好的ref对象绑定到DOM元素或者组件上 */}
                <input type="text" ref={this.txtRef} />
                <button onClick={this.getValue}>获取input的值</button>
            </div>
        )
    }
}