React

以下:携程前端训练营 感觉讲的一般般

React初学者指南

程序员操作虚拟DOM,React操作实际DOM

  • React重要性质:

    1. 组件可组合 组件的目的在于重用
    2. 一个组件独立于其他组件,修改一个组件的时候不相干的组件不会互相干扰
  • React项目的创建:

    1. Create React App npx create-react-app my-app
      • 使用bable和webpack编译和打包代码,可以使用ESLint来检测代码
    2. Vite
      • 使用ESBuild代替webpack
    3. Next.js
  • npm和npx
    npx是一个由Node.js官方提供的用于快速执行npm包中的可执行文件的工具。它可以帮助我们在不全局安装某些包的情况下,直接运行该包提供的命令行工具。npx会在执行时,检查本地项目中是否安装了对应的依赖,如果没有安装则会自动下载安装,并执行命令。如果本地已经存在该依赖,则直接执行命令。

    npx 不会像 npm 或 yarn 一样将包下载到本地的 node_modules 目录中。相反,它会在执行命令时,在本地缓存中寻找并下载包,然后执行该包中的命令。这样可以避免在开发过程中在全局安装大量的包,同时也可以确保使用的是最新版本的包。

    npx会在执行完命令后删除下载的包。这是因为npx会在执行命令之前,将需要执行的包下载到一个临时目录中,并在执行完毕后删除该目录。这样可以避免在本地留下不必要的依赖包。如果需要保留依赖包,可以使用–no-cleanup选项来禁止删除下载的包。

  • React 常用功能:

    • JSX
    • Compoents
    • Props and state
    • Lists,keys,and events
    • Core React Hooks(useState,useEffect)
    • React Context 包括useContext
    • 如何编写自定义React hook
    • Rending and re-rending
    • Pure functions
    • Side effects
  • React常用类库

    • 状态管理类库:Zustand
    • 样式:TailwindCSS
    • 路由:React Router
    • 数据获取:React Query
    • 对于表单:使用React Hook Form
  • 每个js文件中的export default function都表示是该层的顶层组件,只能有一个

React 核心概念

React元素

我们使用JSX特性来编写React元素。因为JSX实际上只是JavaScript函数(而不是HTML),所以与HTML不同,单标记元素(如img元素)必须是自关闭的。它们必须以正斜杠/结尾:

1
2
3
<img src="my-image.png" />
<br />
<hr />

JSX是构造React应用程序最常用的方式,但它不是React所必需的,React.createElement()函数和JSX语言是一一对应的

1
2
3
4
/* JSX是使用React.createElement()函数的更简单方法
换句话说,React中的下面两行代码是一样的: */
<div>Hello React!</div> // JSX syntax
React.createElement('div', null, 'Hello React!'); // createElement 语法

JSX不能被浏览器理解。它需要被编译成浏览器可以理解的普通JavaScript。最常用的JSX编译器称为Babel。

总结JSX:

JSX

JSX中可以嵌套React组件;react组件必须以大写字母开头,HTML标签必须是小写字母开头;组件必须返回JSX

  • 什么是React组件?(见下)
  • 如何实现嵌套?只要将React组件名嵌套到别的组件即可
    1
    2
    3
    4
    5
    6
    7
    8
    export default function MyApp() {
    return (
    <div>
    <h1>Welcome to my app</h1>
    <MyButton />
    </div>
    );
    }

React组件

React组件名必须是以大写字母开头,React组件时返回标签的JS函数,如下:

1
2
3
4
5
function MyButton() {
return (
<button>I'm a button</button>
);
}

组件之间的值传递

React组件可以接受传递给它们的称为props的数据,props从父组件传递给子组件;JS中的任何值都可以作为props传递,包括其它元素和组件;有两种传递方式,一种是作为组建的属性传递,第二种是放在组件的开始标签和结束标签之间传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//第一种方法:作为属性传递数据
function App() {
return <User name="John Doe" />
}
function User(props) {
return <h1>Hello, {props.name}</h1>; // Hello, John Doe!
}
//第二种方法:在组件开始结束标签之间传递
function App() {
return (
<User>
<h1>Hello, John Doe!</h1>//传递了一个元素
</User>
);
}
function User({ children }) {
return children; // Hello, John Doe!
}

条件渲染

  1. 使用if语句:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    let content;
    if (isLoggedIn) {
    content = <AdminPanel />;
    } else {
    content = <LoginForm />;
    }
    return (
    <div>
    {content}
    </div>
    );
  2. 使用三元运算符,直接在JSX部分使用
    1
    2
    3
    4
    5
    6
    7
    <div>
    {isLoggedIn ? (
    <AdminPanel />
    ) : (
    <LoginForm />
    )}
    </div>

列表渲染

使用for循环或者array的map()函数

1
2
3
4
5
6
7
8
9
10
11
//返回值,使用大括号表示变量
function SoccerPlayers() {
const players = ["Messi", "Ronaldo", "Laspada"];
return (
<div>
{players.map((playerName) => (
<SoccerPlayer key={playerName} name={playerName} />
))}
</div>
);
}

JSX语法

JSX是构造React应用程序最常用的方式,但它不是React所必需的,React.createElement()函数和JSX语言是一一对应的

1
2
<div>Hello React!</div> // JSX syntax
React.createElement('div', null, 'Hello React!'); // createElement 语法
  1. 标签必须闭合,只有一个标签的img input br元素必须以正斜杠结尾;双标签的JSX元素必须要有结束标签或者尾随正斜杠结束
  2. 组件不能返回多个JSX标签,标签必须包裹在同一个共享的父亲级中,使用<div>...</div> 或使用空的 <>...</>包裹
  3. JSX属性的命名和HTML属性不同,为了区分JS语法,一些可能出现在元素中的JS中的保留字必须改名,比如元素中的class属性要更改为className
  4. 在多行编写JSX元素,必须以括号括起来(不管JSX元素是一个变量还是函数返回值);JSX中注释用花括号括起来
  5. React元素内联样式:内联样式要使用两组花括号,内联样式不是普通字符串,是对象属性,即将样式整体作为一个有键值对的复杂对象处理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <img
    className="avatar"
    src={user.imageUrl}
    alt={'Photo of ' + user.name}
    style={{
    width: user.imageSize,
    height: user.imageSize
    }}
    />
  6. JSX嵌入动态值:用花括号括起来
    1
    2
    3
    return (
    <h1>{user.name}</h1>
    );
  7. 元素的响应事件:响应事件可以直接在组件中声明事件处理函数来响应事件,直接将函数以参数传递给事件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function MyButton() {
    function handleClick() {
    alert('You clicked me!');
    }

    return (
    <button onClick={handleClick}>
    Click me
    </button>
    );
    }

    注意,react中如果元素响应事件需要传参,最好写成箭头函数
    传递一个函数(正确) 调用一个函数(错误)
    <button onClick={() => alert('...')}> <button onClick={alert('...')}>

React应用

1. ReactDOM.render():通过将应用挂载到HTML元素上来渲染(显示)应用
2. JSX元素:称为“根节点”,因为它是应用程序的根节点。意思是,渲染它将渲染其中的所有子元素
3. HTML (DOM)元素:应用程序在HTML页面中插入的位置。元素通常是一个id为“root”的div,位于index.html文件中。

React上下文

props是级级传递的,为了避免某些不需要改变量的组件去作为“中间人”,使用React中的createContext函数创建一个组件。

const NameContext = createContext('');

生产者(父)使用NameContext.provider包裹,传递的值放在value中,如传递多值,则打包称为一个对象;消费者使用NameContext.Consumer包裹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function App() {
return (
<NameContext.Provider value="John Doe">
<Body />
<NameContext.Provider>
);
}
function Body() {
return <Greeting />;
}
function Greeting() {
return (
<NameContext.Consumer>
{name => <h1>Welcome, {name}</h1>}
</NameContext.Consumer>
);
}

react 事件处理

不能监听react组件上的事件,只能监听JSX元素上的事件,最基本的react事件是`onClick,onChange,onSubmit`
- onClick 处理JSX元素(按钮)上的单击事件
- onChange 处理键盘事件(即用户输入或文本区域)
- onSubmit 处理来自用户的表单提交

React钩子函数

以use开头的函数被称为Hook;Hook 比普通函数更为严格。只能在组件(或其他 Hook)的 顶层 调用 Hook。如果你想在一个条件或循环中使用 钩子函数,请提取一个新的组件并在组件内部使用它。

useState

定义钩子的时候,useState函数中传入的值就是初始值,一般会按照[something, setSomething]这样命名

1
2
3
4
5
import { useState } from 'react';
function MyButton() {
const [count, setCount] = useState(0);
// ...
}
  • 状态提升:如果想让拥有hook的两个组件共享数据,则需要将各个按钮的 state “向上” 移动到最接近包含所有按钮的组件之中。在最大的组件中声明好state,接着把对应的something和setSomething向下传递给子组件。

useEffect

  • useEffect 是一个 React Hook,它允许你 将组件与外部系统同步
  • useEffect(setup, dependencies?)
    • setup 函数 ,其 setup 代码 用来连接到该系统。它应该返回一个 清理函数(cleanup),其 cleanup 代码 用来与该系统断开连接。
    • 一个 依赖项列表,包括这些函数使用的每个组件内的值。
  • 使用场景:参考
    1. 不传依赖项:useEffect在每次渲染后都执行
    2. 依赖项为空数组:希望只在第一次渲染之后执行
      • 设置定时器,避免定时器每次渲染都重新计时
      • 进行数据请求【可以调用Ajax】
      • 从 URLSearchParams 获取数据,用于初始化 state。
    3. 依赖项为非空数组:在每次渲染后,非空数组上的 state 有更新时,就会执行 EffectCallback,即 useEffect 传入回调函数。

useRef

  • useRef 是一个 React Hook,它能帮助引用一个不需要渲染的值。可以直接通过该hook访问JSX元素。
  • 可以通过 ref 操作 DOM
    当 React 创建 DOM 节点并将其渲染到屏幕时,React 将会把 DOM 节点设置为 ref 对象的 current 属性。当节点从屏幕上移除时,React 将把 current 属性设置回 null。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import { useRef } from "react";

    function Header() {
    const inputRef = useRef(); //参数为初始值=
    window.addEventListener("keydown", (event) => {
    if (event.code === "KeyK" && event.ctrlKey) {
    event.preventDefault();
    inputRef.current.focus();
    }
    });
    //将 ref 对象作为 ref 属性传递给想要操作的 DOM 节点的 JSX:
    return <input ref={inputRef} />
    }

useContext

  • useContext 是一个 React Hook,可以让你读取和订阅组件中的 context。
  • 返回值:它被确定为传递给树中调用组件上方最近的 SomeContext.Provider 的 value。如果没有这样的 provider,那么返回值将会是为创建该 context 传递给 createContext 的 defaultValue。
  • useContext() 总是在调用它的组件** 上面 寻找最近的 provider。它向上搜索, 不考虑 **调用 useContext() 的组件中的 provider。
  • 应用场景:上下文:提供一种比标准context更为简单的方式
    • provider还是老方式,consumer可以直接通过useContext(context名)来获取value

useCallback

  • useCallback 是一个允许你在多次渲染中缓存函数的 React Hook。防止重新创建函数影响应用性能。
  • 用法:useCallback(fn, dependencies)
    • 其中dependencies:有关是否更新 fn 的所有响应式值的一个列表。响应式值包括 props、state,和所有在你组件内部直接声明的变量和函数。
  • 使用场景:跳过多次渲染,提升性能:useCallback 在多次渲染中缓存一个函数,直至这个函数的依赖发生改变
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import { useCallback } from 'react';

    function ProductPage({ productId, referrer, theme }) {
    const handleSubmit = useCallback((orderDetails) => {
    post('/product/' + productId + '/buy', {
    referrer,
    orderDetails,
    });
    }, [productId, referrer]);
    //...

useMemo

  • useMemo 是一个 React Hook,它在每次重新渲染的时候能够缓存计算的结果
  • 用法:const cachedValue = useMemo(calculateValue, dependencies)
    • calculateValue必须是一个没有任何参数的 calculation 函数,像这样 () =>,并且返回任何你想要的计算结果。
    • 类似地,dependencies中记录所有在 calculateValue 函数中使用的响应式变量组成的数组。

自定义hook

react错误捕捉

参考

React库

axios

发起请求 在useEffect里,一般放get,其他放单独函数里axios.put/post/delete.then

redux

状态管理库,提供了store用来管理大量数据

  • 创建store需要使用import { createStore } from 'redux';

    Don’t create more than one store in an application!

  • createStore函数
    接受三个参数:

    • 第一个参数是一个函数,通常被称为 reducer(必需的);该函数一般有两个参数 state和action
    • 第二个参数是状态state的初始值(可选)(一般在reducer函数里初始化)
    • 第三个参数是一个增强器enhancer,如果有的话,我们可以传递中间件(可选的)
    1
    2
    3
    4
    5
    6
    7
    import { createStore } from 'redux';
    const reducer = (state = 0, action) => {
    console.log('reducer called');
    return state;
    };
    const store = createStore(reducer);

  • 订阅store中的变化
    使用store.subscribe函数
    一旦我们将reducer传递给createStore函数,它就会立即被调用。

  • 改变store
    更改存储的唯一方法是分派操作。如下:

    1
    2
    3
    4
    5
    6
    7
    8
    store.dispatch({
    type: 'INCREMENT'
    })

    store.dispatch({
    type: 'INCREMENT',
    payload: 1
    });

    上述函数向store发送一个类型为INCREMENT的action。dispatch函数接受一个对象作为参数,这个对象被称为一个action。该action必须具有如上所示的type属性。如果你没有传递type属性,那么你会得到一个错误。type是自定义的,但是建议使用大写和下划线分隔。

    • 注意,reducer中不能更改原来的state
    • 还可以在dispatch函数中添加额外的信息作为action的一部分,可以添加payload,获取payload可以使用action.payload

Router

  • React Router DOM是针对web应用的,React Router Native是针对使用React Native制作的移动应用的。npm install react-router-dom
  • 导入import { BrowserRouter as Router } from 'react-router-dom';导入BrowserRoute时,通常将其别名(重命名)为“Router”。如果我们想在整个应用程序中提供路由,它需要被包裹在整个组件树中。
  • Route组件:每个路由提供至少两个属性,path和component(或render):
    • path 属性指定一个路由位于应用程序的哪个路径上。
      例如,对于一个about页面,我们可能希望该路由可以在路径’/about’中访问。
    • render或component属性用于显示路径的特定组件。component属性只能接收到一个给定组件的引用,而render通常用于应用一些条件逻辑来呈现一个或另一个组件。对于render,你可以使用对组件的引用,也可以使用函数
    • 也可以完全不要render和component属性,使用组件作为route的子组件
    • 如果想让一个组件(比如导航栏)在每个页面上都可见,把它放在browser router中,要声明的路由的上方(或下方)
  • Switch Component
    1. 使用excat解决同时出现两个页面的问题:<Route exact path="/" component={Home} />
    2. 使用"react-router-dom"中的switch组件:switch组件查看它的所有子路由,并显示其路径与当前URL匹配的第一个子路由,一次显示一个页面。
  • 404 Route
    <Route path="*" component={NotFound} />
  • Link Component
    一般在的Navbar中,创建link,指定to属性进行跳转,可以提供内联样式
    1
    2
    3
    4
    5
    6
    7
    8
    function Navbar() {
    return (
    <nav>
    <Link to="/">Home</Link>
    <Link to="/about">About</Link>
    </nav>
    )
    }
  • NavLink Component
    允许创建active link的样式,可以使用activeClassName 属性或者直接使用行内样式activeStyle
  • Redirect Component
    重定向组件 <Redirect to="/" />
  • useHistory Hook
    • 它们可以被作为普通的React hook调用,我们可以使用它们的值。在我们的任何组件顶部调用它,并获得与我们组件相关的数据。比如他们所在的pathname,以及query parameters等,所有的location数据都可以从history.location中访问。
    • 可以使用history.push完成重定向
  • useLocation Hook
    • 如果你只想要location数据,那么你所需要做的就是调用useLocation来获取与history. location数据相同的对象
  • useParams Hook + Dynamic Routes
    • 动态路由写法:在参数之前加上冒号作为前缀/blog/:postSlug
    • 使用useParams hook访问任何路由参数,useParams将返回一个对象,该对象将包含与我们的路由参数匹配的属性
  • useRouteMatch Hook
    • 想知道给定的组件是否在某个页面上,可以使用useRouteMatch hook

React Native

  • 架构:
    • 旧:JSC环境中运行的rn业务代码 通过Bridge完成js代码和原生端API和组件的调用
    • 新:JSI: JavaScript Interface 支持JS对象持有C++的引用,同步调用
  • 核心组件:

基础

  • 样式:推荐少用内联,多用StyleSheet.create({})
  • 布局:主要布局基于Flexbox,通过flexDirection(默认垂直排序),使用justifyContent和alignItems控制子元素在主轴和次轴的排列方式,RN支支持relative(默认)和absolute两种position设置;宽、高度可以设置自适应(默认)、百分比、固定值
  • Props:组件的属性,父子组件之间的数据传输;
    • props是不可变的,外部属性的变更也会引起组件的渲染
  • state:和react一样
  • 交互
    • 触摸事件:
      • 点击onPress.onLongPress onDoublePress、滑动等
      • 事件处理与WEB开发中的事件处理非常相似
      • 事件冒泡和捕获遵循DOM标准
      • 以便使用Touchable系列组件响应事件
    • 动画
      • Animated:声明的形式定义动画的输入和输出;支持组合、跟踪状态值、跟踪手势
      • LayoutAnimation:全局范围;更新flexbox布局
    • 导航
      • 官方导航库:Reat Navigation安装:npm install @react-navigation/native @react-navigation/stack
      • 提供多种导航组件
  • 网络请求
    • 使用useEffect()中的fetch
      1
      2
      3
      4
      5
      6
      7
      useEffect(() => {
      fetch('https://reactnative.dev/movies.json')
      .then((response) => response.json())
      .then((json) => setData(json.movies))
      .catch((error) => console.error(error))
      .finally(() => setLoading(false));
      }, []);
  • 生命周期
    • 组件生命周期、响应式Effect生命周期、页面生命周期
    • 组件挂在mounting(轻量初始化)->页面更新Updating->Unmounting
    • 一般使用函数组件
    • 对于整个页面生命周期:RN没有提供页面状态变化的处理(切后台等),解决方法:import{useNavigation,useFocusEffect}from '@react-navigatio /native'
  • 环境搭建:使用后Expo

React
https://mapllle.site/2024/02/13/frontend/React/
作者
MAple
发布于
2024年2月13日
许可协议