React 快速入门

react

JSX语法

几乎和html一样,有些属性名称不同

class => className
<div style={{ background: "red" }}>  # 内嵌样式

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

组件

函数组件(无状态组件)
约定1:函数名字必须大写字母开头
约定2:函数必须有返回值
返回null表示不渲染内容
类组件(有状态组件)

可以通过类属性(state)保存状态

约定1:类名必须大写字母开头
约定2:类组件必须继承React.Compont
约定3:类组件必须提供render(),返回值就是组件的jsx
import使用

如果组件是export default 导出,就不用{},一个模块中只能有一个默认导出export default

如果是具名导出 export user; 就需要{user},名字保持一致

import Home from './pages/Home'
import {user} from './pages/CityList'
import './index.scss'  // 直接引入样式文件

事件处理

事件绑定

在jsx中,对元素标签绑定事件

语法:on+事件={事件处理程序}, 比如onClick = {handleClick}

事件对象

在事件处理程序中,可以设置第一个参数获取事件对象。react事件对象兼容所有的浏览器,不需要额外处理

function handleClick(e){e.preventDefault()}
OnClick函数传参
<button onClick={jumpToDeposit(item)}>Deposit</button> # 这样写,button渲染的时候就执行了jumpToDeposit(),点击的时候不会执行
<button onClick={(e)=>{jumpToDeposit(item)}}>Deposit</button> # 这样写才行,button渲染时得到闭包函数,函数里面执行jumpToDeposit()

组件的state

只有类组件有state,state是私有的,只有组件内部能使用,this.state获取当前主机的所有state数据。

修改state的值,setState()作用:1.修改state值,2.更新UI

this.setState({count:this.state.count+1})
//不能直接修改
this.state.count++ //错误

组件通信——props

传递数据:在组件标签添加属性

函数组件通过props参数实现组件数据接收,类组件通过this.props属性获取数据

props是只读对象,不能修改

props可以接受任意类型的数据

props.children属性特指组件标签包含的子节点

props可以设置默认值,

<Hello name="jack" age={19}>这是组件子节点</Hello>

func Hello(props) {
    return (
    <div>
        接收到数据{props.name}
        组件中的子节点{props.children}
        组件的默认值{props.pageSize}
    </div>
    )    
}

// 给组件添加默认值
Hello.defaultPros={
    pageSize:10
}
父组件传递数据给子组件

父组件把传递的数据放在state中

给子组件添加属性,并且使用state赋值

子组件通过props获取数据

class Hello extends React.Component{    
    state = {
        list:[]
    }  
    render(){
        return (<Child list={this.state.list} />)
    }
}
子组件传递数据给父组件

父组件通过回调函数接收数据,父组件先把回调函数传递给子组件。

子组件通过props获取父回调函数

子组件调用父回调函数,并且传递数据即可。

class Hello extends React.Component{ 
    receiveMsg =(data)=>{
        console.log("接收到数据", data)
    }
    render(){
        return (<Child receiveMsg={this.receiveMsg} />)
    }
}

class Child extends React.Component{
    state={
        msg:"hello world"
    }
    handleClick = ()=>{
        this.props.receiveMsg(this.state.msg)
    }
    render(){
        return (<div onClick={this.handleClick}>发送数据给父组件</div>)
    }
}
兄弟组件通信

状态提升:把需要传递的数据放在共同的父组件中

父组件把状态传递给读子组件

父组件把修改状态方法传递给写子组件

跨组件通信

Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props。

组件的生命周期

只有类组件才有生命周期,每个阶段都有钩子函数,方便我们在不同时期做操作。

1.创建时(加载时),会执行三个函数

constructor() -> render() ->componentDidMount()
钩子函数 触发时机 一般使用
constructor 创建组件时 初始化state
render() 每次组件渲染时触发 渲染UI, 不能执行setState()
componentDidMount() 组件挂载(完成DOM渲染)后 1.发送网络请求
2.DOM操作
  1. 更新时

组件接收props, setState(), forceUpdate()执行这些操作时,会触发更新

render() -> componentDidUpdate()
钩子函数 触发时机 一般使用
render() 每次组件渲染时触发 渲染UI, 不能执行setState()
componentDidMount() 组件挂载(完成DOM渲染)后 1.发送网络请求
2.DOM操作
3.执行setState必须放在if条件中,不然会死循环

3.卸载时

componentWillUnmount(), 一般是执行清理工作,比如定时器

组件复用

比如复用state和操作state的方法

两种处理方法,

注意:这两种方式不是新API,而是利用React自身特点的编码技巧,演化而成的固定模式(写法)

1.render props模式

调用组件时,从外面传入render逻辑,不同的render逻辑,就可以实现同一个组件,但是不同的展示。实现了state共用,但是ui渲染不同的写法。

2.高阶组件(HOC)

React原理

setState()的说明

这是异步函数,使用该语法,在setState()后面的代码注意state的值不会马上修改的。

setState()会执行两个步骤,1.修改state的值 2.更新render渲染, 可以多次执行setState(),但是ui只会触发一次重新渲染。

// 通过传入回调函数来更新state
this.setState((state,props)=>{
    return {count: state.count+1}
})
// 想在状态更新后并且重新渲染后,立即执行逻辑,可以在setState第二个参数传入callback
this.setState(
    (state,props)=>{},
    ()=>{
       document.title="更新state后" 
    }
)
JSX语法的转化过程

JSX仅仅是createElement()方法的语法糖,JSX语法会被@babel/preset-react插件编译为createElement()方法。

createElement()方法返回一个React元素(一个js对象),描述页面展示的内容。

组件更新机制

父组件重新渲染时,也会重新渲染子组件。

组件性能优化

减轻state

只存储组件渲染相关的数据,可以放到this对象中。

避免不必要的重新渲染
shoudComponentUpdate(nextprops,nextState) //钩子函数,返回fasle表示组件不会重新渲染,可以对比this.state和nextState的值,判断有些情况是不用重新渲染的
虚拟DOM和Diff算法

React的state修改后,会重新渲染整个组件,实际在底层,只会修改变化的虚拟DOM(就是js对象,描述DOM的一些属性),虚拟DOM可以让React脱离浏览器环境,做到跨平台应用。

React路由

现代的前端大多数SPA(单页应用程序),为了有效的使用单个页面来管理原来多个页面的功能,前端路由应运而生。

前端路由功能:让用户从一个视图导航到另外一个视图。

前端路由是一套映射规则,在React中,URL路径组件的对应关系

使用步骤
yarn add react-router-dom

导入路由的三个核心组件Router,Route,Link

import {BrowserRouter as Router, Routes, Route, Link} from 'react-router-dom'

使用Router包裹整个应用

<Router>
        <Link to="/first">页面一 </Link>
        <Link to="/second">页面二</Link>
        <Routes>
            <Route path="/first" element={<Page1/>} />
            <Route path="/second" element={<Page2/>} />
        </Routes>
</Router>

Link传参,通过useLocation读取参数

<Link to='/params' state={{id:1}} />

// 接受路由参数
import {useLocation} from 'react-router-dom'
function UseParams() {
    const location = useLocation()
    console.log(location.state.id)
    return (
        <div>UseParams</div>
    )
}
export default UseParams
常用组件的说明

BrowserRouter: 包裹整个应用,一个React应用只需要使用一次。

Link组件:路由的入口,会被编译为一个a标签。

<Link to="/first" 页面一>

Route: 路由的出口,展示对应的组件的视图。

<Routes>
    <Route path="/first" element={<Page1/>} />
</Routes>
路由的执行过程
  1. 点击Link会修改浏览器地址栏的url
  2. React路由监听浏览器的url
  3. React路由遍历所有的Route组件,使用路由规则(path)与pathname进行匹配
  4. 当路由规则能够找到对应的pathname是,就展示对应的Route组件的内容
编程式导航:

通过JS代码实现页面跳转

嵌套路由

页面中嵌套页面

layout页面是一级路由,about,content是二级路由

layout
    about
  content

创建一级路由页面Layout

import {Outlet} from 'react-router-dom'

function Layout() {
    return (
        <div>
            Layout
            <Outlet/> // 二级路由出口
        </div>
    )
}

export default Layout;

定义嵌套路由

 // 1.定义嵌套路由
<Route path='/' element={<Layout />}>
    <Route path='about' element={<About />} />
    <Route path='content' element={<Content />} />
</Route>
  1. 默认二级路由

    添加index属性,删除自己的path,这样访问/时,默认显示的二级路由是About

<Route path='/' element={<Layout />}>
    <Route index element={<About />} /> 
    <Route path='content' element={<Content />} />
</Route>
  1. 404路由
<Routes>
   <Route path='/login' element={<Login/>} />
   {/* 所有路由都没有匹配时,显示nofound组件 */}
   <Route path='*' element={<NoFound />} />
 </Routes>
编程式导航

在组件中进行路由跳转

// 1.import 跳转函数
import { useNavigate } from 'react-router-dom';
function Login() {
    // 2. 获取跳转函数
    const navigate = useNavigate()
    function goAbout() {
        // 3.执行跳转
        navigate('/about')
    }
    return (
        <div>
            Login
            <button onClick={goAbout}>跳转到about</button>
        </div>
    )
}
export default Login;

跳转传参数

1.searchParams传参
navigate(/about?id=1)
读取取参数
const [params] = useSearchParams() // 返回的是数组
let id = params.get('id')

2. 通过state传参
const jumpToDeposit = (item)=>{
    navigate('/deposit', {state:{id:item.ID,
      playA:item.PlayA,
      playB:item.PlayB,
      playAID:item.PlayAID,
      startTime:item.StartTime,
      contractAddr:item.ContractAddr
    }})
  }
读取参数
const location = useLocation()
console.log(location.state) // 读取到传递的对象
本作品采用《CC 协议》,转载必须注明作者和本文链接
用过哪些工具?为啥用这个工具(速度快,支持高并发...)?底层如何实现的?
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!