初始化
-
创建react项目
npx create-react-app 项目名称
-
运行
npm start
JSX
- 概念:JSX是javascript XML的缩写,表示在js中写html
JSX中使用表达式
const name = '柴柴'
<h1>你好,我叫{name}</h1> // <h1>你好,我叫柴柴</h1>
注意:能在其中使用的是表达式,if、switch等是语句,不可写在{}中
JSX列表渲染
实现:使用数组的map
方法
const lists = [
{ id: 1, name: '1' },
{ id: 2, name: '2' },
{ id: 3, name: '3' }
]
function App() {
return (
<div className="App">
<ul>
{
lists.map(item => <li key={item.id}>{item.name}</li>)
// 需要为遍历项添加 key 属性
}
</ul>
</div>
)
}
export default App
- key 在 HTML 结构中是看不到的,是 React 内部用来进行性能优化时使用
- key 在当前列表中要唯一的字符串或者数值(String/Number)
- 如果列表中有像 id 这种的唯一值,就用 id 来作为 key 值
- 如果列表中没有像 id 这种的唯一值,就可以使用 index(下标)来作为 key 值
JSX条件渲染
实现:可以使用 三元运算符
或 逻辑与(&&)运算符
const flag = true
function App() {
return (
<div className="App">
{/* 条件渲染字符串 */}
{flag ? 'react真有趣' : 'vue真有趣'}
{/* 条件渲染标签/组件 */}
{flag ? <span>this is span</span> : null}
</div>
)
}
export default App
JSX样式处理
- 行内
<div style={{ color: 'red' }}>this is a div</div>
// 更优解
// 使得模板更为精简
const styleObj = {
color:red
}
function App() {
return (
<div className="App">
<div style={ styleObj }>this is a div</div>
</div>
)
}
export default App
- 动态类名
.title {
font-size: 30px;
color: blue;
}
import './app.css'
const showTitle = true
function App() {
return (
<div className="App">
// 在此处使用三元表达式动态判定
<div className={ showTitle ? 'title' : ''}>this is a div</div>
</div>
)
}
export default App
其他注意事项
- JSX必须有一个根节点,如果没有根节点,可以使用
<>
(幽灵节点)替代 - 所有标签必须形成闭合,成对闭合或者自闭合都可以
- JSX中的语法更加贴近JS语法,属性名采用驼峰命名法
class -> className
for -> htmlFor
- JSX支持多行(换行),如果需要换行,需使用
()
包裹,防止bug出现
组件
概念:在vue中,也贯彻了组件化开发的思想,组件化开发能够帮助我们更精确的修改代码,维护性更高。在react中,分为函数组件和类组件两种
函数组件
概念:使用 JS 的函数(或箭头函数)创建的组件,就叫做函数组件
// 定义函数组件
function HelloFn () {
return <div>这是我的第一个函数组件!</div>
}
类组件
概念:使用 ES6 的 class 创建的组件,叫做类(class)组件
// 引入React
import React from 'react'
// 定义类组件
class HelloC extends React.Component {
render () {
return <div>这是我的第一个类组件!</div>
}
}
function App () {
return (
<div className="App">
{/* 渲染类组件 */}
<HelloC />
<HelloC></HelloC>
</div>
)
}
export default App
1、不管是类组件还是函数组件,名称都必须首字母大写,react内部会根据这个名称来判断是组件还是标签。
2、函数组件必须含有返回值,若不需要返回内容啧return null
3、类组件必须继承父类,从而使用父类中提供的方法属性
4、类组件必须提供render方法并含有返回值。
事件绑定
1、如何绑定事件
- 语法:on + 事件名称 = { 事件处理程序 }
<div onClick={ onClick }></div>
// 使用驼峰
// 函数组件
function HelloFn () {
// 定义事件回调函数
const clickHandler = () => {
console.log('事件被触发了')
}
return (
// 绑定事件
<button onClick={clickHandler}>click me!</button>
)
}
2、获取事件对象
- 事件对象e:只需要在事件回调函数中补充一个形参e即可拿到。
- 额外参数:改造事件绑定为箭头函数 在箭头函数中完成参数的传递
import React from "react"
// 如何获取额外的参数?
// onClick={ onDel } -> onClick={ () => onDel(id) }
// 注意: 一定不要在模板中写出函数调用的代码 onClick = { onDel(id) }
const TestComponent = () => {
const list = [
{
id: 1001,
name: 'react'
},
{
id: 1002,
name: 'vue'
}
]
const onDel = (e, id) => {
console.log(e, id)
}
return (
<ul>
{list.map(item =>(
<li key={item.id}>
{item.name}
<button onClick={(e) => onDel(e, item.id)}>x</button>
</li>
))}
</ul>
)
}
function App () {
return (
<div>
<TestComponent />
</div>
)
}
export default App
注意:类组件的事件绑定和函数组件并没有太大差异,但在类组件中,存在this指向问题,因此,我们通常这么执行。
// 类组件中的事件绑定
// 定义的时候: class Fields语法
// 使用的时候: 需要借助this关键词获取
// 注意事项: 之所以要采取class Fields写法是为了保证this的指向正确 永远指向当前的组件实例
import React from "react"
class CComponent extends React.Component {
// class Fields
clickHandler = (e, num) => {
// 这里的this指向的是正确的当前的组件实例对象
// 可以非常方便的通过this关键词拿到组件实例身上的其他属性或者方法
console.log(this)
}
clickHandler1 () {
// 这里的this 不指向当前的组件实例对象 undefined 存在this丢失问题
console.log(this)
}
render () {
return (
<div>
<button onClick={(e) => this.clickHandler(e, '123')}>click me</button>
<button onClick={this.clickHandler1}>click me</button>
</div>
)
}
}
function App () {
return (
<div>
<CComponent />
</div>
)
}
export default App
组件状态
注:在React hook出来之前,函数式组件是没有自己的状态的,所以我们首先通过类组件来讲解
1、状态
- 通过class的实例属性state来初始化
- state的值是一个对象结构,表示一个组件可以有多个数据状态
- 通过this.state来获取状态
class Counter extends React.Component {
// 初始化状态
state = {
count: 0
}
render() {
// 读取状态
return <button>计数器{this.state.count}</button>
}
}
2、修改状态
- 语法
this.setState({ 要修改的部分数据 })
- setState方法作用
-
- 修改state中的数据状态
- 更新UI
- 思想
数据驱动视图,也就是只要修改数据状态,那么页面就会自动刷新,无需手动操作dom - 注意事项
不要直接修改state中的值,必须通过setState方法进行修改
class Counter extends React.Component {
// 定义数据
state = {
count: 0
}
// 定义修改数据的方法
setCount = () => {
this.setState({
count: this.state.count + 1
})
}
// 使用数据 并绑定事件
render () {
return <button onClick={this.setCount}>{this.state.count}</button>
}
}
3、react状态不可变
概念:不要直接修改状态的值,而是基于当前状态创建新的状态值
概念**:不要直接修改状态的值,而是基于当前状态创建新的状态值
-
简单数据类型:使用this.setState({…})
-
数组类型/对象类型:
this.setState({ count: this.state.count + 1 list: [...this.state.list, 4], person: { ...this.state.person, // 覆盖原来的属性 就可以达到修改对象中属性的目的 name: 'rose' } })
表单组件
表单元素一般含有两种处理方式,分别是受控组件和非受控组件。其中受控组件常常使用。其意为input框自己的状态被React组件状态控制
-
受控组件实现步骤
以获取文本框的值为例,受控组件的使用步骤如下:
- 在组件的state中声明一个组件的状态数据
- 将状态数据设置为input标签元素的value属性的值
- 为input添加change事件,在事件处理程序中,通过事件对象e获取到当前文本框的值(
即用户当前输入的值
) - 调用setState方法,将文本框的值作为state状态的最新值
其中a、b步骤其实就相当于我们vue中的v-model,这个过程基本也就等同于vue中的v-model封装。
import React from 'react' class InputComponent extends React.Component { // 声明组件状态 a步骤 state = { message: 'this is message', } // 声明事件回调函数 c步骤 changeHandler = (e) => { this.setState({ message: e.target.value }) } render () { return ( <div> {/* 绑定value 绑定事件 b、d步骤 */} <input value={this.state.message} onChange={this.changeHandler} /> </div> ) } } function App () { return ( <div className="App"> <InputComponent /> </div> ) } export default App
-
非受控表单组件
非受控组件就是通过手动操作dom的方式获取文本框的值,文本框的状态不受react组件的state中的状态控制,直接通过原生dom获取输入框的值。
- 导入
createRef
函数 - 调用createRef函数,创建一个ref对象,存储到名为
msgRef
的实例属性中 - 为input添加ref属性,值为
msgRef
- 在按钮的事件处理程序中,通过
msgRef.current
即可拿到input对应的dom元素,而其中msgRef.current.value
拿到的就是文本框的值
import React, { createRef } from 'react' class InputComponent extends React.Component { // 使用createRef产生一个存放dom的对象容器 msgRef = createRef() changeHandler = () => { console.log(this.msgRef.current.value) } render() { return ( <div> {/* ref绑定 获取真实dom */} <input ref={this.msgRef} /> <button onClick={this.changeHandler}>click</button> </div> ) } } function App () { return ( <div className="App"> <InputComponent /> </div> ) } export default App
- 导入