Skip to content

React 基础

一、React 介绍

什么是 React?

React 有 Meta 公司研发,是一个用于 构建 Web 和原生交互界面的库

  • 开发 B 端应用
  • 开发原生应用

React 优势

相较于传统基于 DOM 开发的优势

  • 组件化的开发方式

  • 不错的性能

相较于其他前端框架的优势

  • 丰富的生态

  • 跨平台支持

  • 社区活跃

二、React 开发环境准备

使用 create-react-app 快速搭建开发环境。create-react-app是一个快速创建 React 开发环境的工具,底层由 webpack 构建,封装了配置细节,开箱即用。

  • 执行命令: npx create-react-app react-basic
  1. npx:Nodejs 工具命令,查找并执行后续的包命令。

  2. create-react-app:核心包(固定写法),创建 React 项目的命令。

  3. react-basic:项目名称。

  • 或者全局安装 create-react-app 工具:
// 全局安装react脚手架
npm i -g create-react-app

// 创建工程
create-react-app react-basic

三、脚手架模版目录介绍

├── README.md
├── package-lock.json
├── package.json
├── public
│   ├── favicon.ico
│   └── index.html HTML模板文件
└── src
    ├── App.js 根组件
    └── index.js 入口文件

四、JSX

4.1 JSX 介绍

** 什么是 JSX**: JSX 是 javascript 和 XML 的缩写,表示在 js 代码中编写 HTML 模版结构,它是 react 中编写 UI 模版的方式

jsx
const message = 'this is message'

function App() {
  return (
    <div>
      <h1>this is title: {message}</h1>
    </div>
  )
}

优势:

  • HTML 的声明式模版写法
  • JS 的可编程能力

** JSX的本质 **: JSX 并不是标准的 JS 语法,它是 JS 的语法扩展,浏览器本身不能识别,需要通过 解析工具解析 才能被浏览器识别

jsx
<div>this is JSX</div>


>>>> babel >>>>

import { jsx as _jsx } from 'react/jsx-runtime'

/*#__PURE__*/_jsx("div", {
    children: "this is JSX"
});

4.2 JSX 语法

在 JSX 中可以通过 大括号{} 识别 JavaScrip 中的表达式,比如常见的变量、函数调用、方法调用等等。

  • 使用引号传递字符串
jsx
function App() {
  return (
    <div>
      this is App
      {/* 使用引号传递字符串 */}
      {'this is message'}
    </div>
  )
}
  • 使用 JavaScrip 变量
jsx
const count = 10
function App() {
  return (
    <div>
      this is App
      {/* 识别js变量 */}
      {count}
    </div>
  )
}
  • 函数调用和方法调用
jsx
function getName() {
  return '张三'
}
function App() {
  return (
    <div>
      this is App
      {/* 函数调用 */}
      {getName()}
      {/* 方法调用 */}
      {new Date().getDate()}
    </div>
  )
}
  • 使用 JavaScript 对象
jsx
function getName() {
  return '张三'
}
function App() {
  return (
    {/* 使用js对象 */}
    <div style={{ color:'red' }}>
      this is App
    </div>
  )
}
  • 在 JSX 中实现列表渲染:可以使用原生 JS 中的 map 方法遍历渲染列表
jsx
const list = [
  {
    id: 1001,
    name: '张三'
  },
  {
    id: 1002,
    name: '李四'
  },
  {
    id: 1003,
    name: '王二'
  }
]

function App() {
  return (
    <div>
      {list.map((v) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </div>
  )
}
  • JSX 中条件判断渲染
jsx
const isLogin = true

function App() {
  return (
    <div className="App">
      {/** 逻辑 与 **/}
      {isLogin && <div>this is span</div>}
      {/** 三元运算 **/}
      {isLogin ? <div>this is span</div> : <div>this is span2</div>}
    </div>
  )
}

export default App

复杂场景的条件判断。 需求:列表中需要根据文章状态适配三种情况,单图、三图和无图三种模式 解决方案: 自定义函数 + if 判断语句

jsx
const articleType = 1 // 0 1 2
function getArticleItemType() {
  articleType === 0 ? '单图' : articleType === 1 ? '三图' : '无图'
}

function App() {
  return <div className="App">{getArticleItemType()}</div>
}

export default App
  • 基础事件绑定

语法:on + 事件名称 = {事件处理程序}, 整体遵循驼峰命名法。

jsx
function App() {
  const handleClick = () => {
    console.log('this is click')
  }
  return <button onClick={handleClick}>this is button</button>
}

export default App

传递自定义参数:事件绑定的位置改造成箭头函数的写法,在执行 clickHandler 实际处理业务函数的时候传递实参

jsx
function App() {
  const handleClick = (name) => {
    console.log('this is click' + name)
  }
  return <button onClick={() => handleClick('张三')}>this is button</button>
}

export default App

同时传递事件对象实参 e 和自定义参数,clickHandler 中声明形参

jsx
function App() {
  const handleClick = (name, e) => {
    console.log('this is click' + name)
  }
  return <button onClick={(e) => handleClick('张三', e)}>this is button</button>
}

export default App

五、React 组件

概念: 一个组件就是用户界面的一部分,它可以有自己的逻辑和外观,组件之间可以互相嵌套,也可以额服用多次

** React组件 **: 一个组件就是首字母大写的函数,内部存放了组件的逻辑和视图 UI,渲染组件只需要把组件当成标签书写即可

jsx
// 组件定义
function Button() {
  // 组件内部逻辑
  return <button>this is button</button>
}

// 使用组件
function App() {
  return <Button />
}

六、基础样式控制

6.1 行内样式(不推荐)

jsx
<div style={{ color: 'red' }}>this is div</div>

6.2 class 类名控制

css
.foo {
  color: red;
}
jsx
import './index.css'

function App() {
  return <div className="foo">this is div</div>
}

七、 受控表单

八、组件通信

概念:组件通信就是组件之间的数据传递,根据组件嵌套关系的不同,有不同的通信方法

8.1 父子组件通信 A -> B

  • 父传子

  • 子传父

8.1.1 父组件传递数据给子组件

父传子

实现步骤:

  • 父组件传递数据 - 在子组件标签上绑定属性

  • 子组件接受数据 - 子组件通过 props 参数接受数据

jsx
function Father() {
  const name = 'this is father'
  return (
    <div>
      <Son name={name} />
    </div>
  )
}
jsx
function Son(props) {
  // props: 对象里面包含了父组件传递过来的所有的数据
  console.log(props)
  return <div>this is son: {props.name}</div>
}

父传子 props 说明:

  1. props 可以传递任意的数据: 数字、字符串、布尔值、数组、对象、函数、JSX

  2. props 是只读对象: 子组件只能读取 props 中的数据,不能直接进行修改,父组件的数据只能由父组件修改

** 特殊的prop children **: 当把内容嵌套在子组件标签中时,父组件会自动在名为 children 的 props 属性中接受该内容

jsx
<Son>
  <span>这是一个span</span>
</Son>

/***
 * props: {
 *  children: <span />
 * }
 */

8.1.2 子组件传递给父组件

子传父

核心思路:在子组件中调用父组件中的函数并传递参数

jsx
function Father() {
  const name = 'this is father'
  // 4. 定义父组件状态变量
  const [msg, setMsg] = useState('')

  // 3. 声明父组件的方法,并且用参数接收子组件传递过来的数据
  const getMsg = (msg) => {
    console.log(msg)
    // 赋值给状态变量
    setMsg(msg)
  }

  return (
    <div>
      {/* 给子组件传递方法函数 */}
      <Son name={name} onGetSonMsg={getMsg} />
      <span>{msg}</span>
    </div>
  )
}
jsx
function Son({ onGetSonMsg }) {
  // 1. 声明需要传给父组件的数据
  const sonMsg = 'this is son'

  return (
    <div>
      this is son: {props.name}
      {/* 2. 调用父组件的方法并传递数据 */}
      <button onClick={() => onGetSonMsg(sonMsg)}>sendMsg</button>
    </div>
  )
}

8.2 兄弟组件通信 B -> C

兄弟组件通信

实现思路:借助 状态提升 机制, 通过父组件进行兄弟组件之间的数据传递

  • A 组件先通过子传父的方式把数据传给父组件

  • 父组件拿到数据后通过父传子的方式在传递给 B 组件

jsx
function App() {
  const [name, setName] = useState('')
  const getMsg = (msg) => {
    console.log(msg)
    setName(msg)
  }
  return (
    <div>
      <A onGetMsg={getMsg} />
      <B />
    </div>
  )
}
jsx
function A({ onGetMsg }) {
  const name = 'this is A component'
  return (
    <div>
      this is A component
      <button onClick={() => onGetMsg(name)}>send</button>
    </div>
  )
}
jsx
function B({ name }) {
  return (
    <div>
      this is B component
      {name}
    </div>
  )
}

8.3 跨层级组件通信 A -> E

跨层级组件通信

使用Context机制跨层级组件通信

  • 使用 createContext 方法创建一个上下文对象 Ctx

  • 在顶层组件(App) 中通过 Ctx.Provider组件 提供数据

  • 在底层组件(B)中通过 useContext 钩子函数获取数据

jsx
const MsgContenxt = createContext()

function App() {
  const msg = 'this is app msg'
  return (
    <div>
      <MsgContenxt.Provider value={msg}>
        <A />
      </MsgContenxt.Provider>
    </div>
  )
}
jsx
function A() {
  return (
    <div>
      this is A component
      <B />
    </div>
  )
}
jsx
function B() {
  const msg = useContext(MsgContenxt)
  return (
    <div>
      this is B component
      {msg}
    </div>
  )
}

九、React.forwardRef

作用: 使用 ref 暴露 DOM 节点给父组件

jsx
import { useRef } from 'react'
import RefExample from './exercise/01Comment/RefExample'

function App() {
  const refExample = useRef(null) 
  const showRef = () => {
    console.log(refExample)
  }
  return (
    <div className="App">
      <button onClick={showRef}>showRef</button> // [!code focus]
      <RefExample ref={refExample} /> // [!code focus]
    </div>
  )
}

export default App
jsx
import { forwardRef } from 'react'

const RefExample = forwardRef((props, ref) => {
  return <input type="text" ref={ref} />
})

export default RefExample

十、useInperativeHandle

作用: 通过 ref 暴露子组件中的方法

jsx
import { useRef } from 'react'
import RefExample from './exercise/01Comment/RefExample'

function App() {
  const refExample = useRef(null)
  const showRef = () => {
    console.log(refExample.current)
    refExample.current.handleFocus() 
  }
  return (
    <div className="App">
      <button onClick={showRef}>showRef</button>
      <RefExample ref={refExample} />
    </div>
  )
}

export default App
jsx
import { useRef, forwardRef, useInperativeHandle } from 'react'

const RefExample = forwardRef((props, ref) => {
  const inputRef = useRef(null) 
  // 实现组件内部的聚焦逻辑方法
  const handleFocus = () => { 
    inputRef.current.focus() 
  } 
  // 暴露函数给父组件调用
  useInperativeHandle(ref, () => ({ 
    return handleFocus 
  }) 
  return <input type="text" ref={inputRef} />
})

export default RefExample