React基础入门

核心概念

1. 创建和嵌套组件

React 应用程序是由 组件 组成的。一个组件是 UI(用户界面)的一部分,它拥有自己的逻辑和外观。组件可以小到一个按钮,也可以大到整个页面

React 组件必须以大写字母开头,而 HTML 标签则必须是小写字母。

function MyButton() {
  return (
    <button>I'm a button</button>
  );
}
export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
    </div>
  );
}
2. 使用jsx

JSX 比 HTML 更加严格。你必须闭合标签,如 <br />。你的组件也不能返回多个 JSX 标签。你必须将它们包裹到一个共享的父级中,比如 <div>...</div> 或使用空的 <>...</> 包裹

function AboutPage() {
  return (
    <>
      <h1>About</h1>
      <p>Hello there.<br />How do you do?</p>
    </>
  );
}
3. 添加样式

在 React 中,你可以使用 className 来指定一个 CSS 的 class。它与 HTML 的

<a href="" title="" target="_blank" class="link">class</a> 属性的工作方式相同

<img className="user" />
.user{
  background:red;
}

内联样式

<div style={{width:"300px",backgroundColor:"red"}}></div>
4. 显示数据

标签中的 { } 内,可以执行 js 代码

const [visiable,setVisiable] = useState<Boolean>(false);
const title = "标题";
return (
 <>
  {
    visiable ? <h1>{ title }</h1> : null
  }
 </>
)

将变量user.imageUrl 赋值给 img 标签的 src 属性,需要使用{} 而非 “”。

<img src="user" />    // 将“user”字符串传递给src
<img src={userPng} /> // 将变量userPng传递给src
5. 条件渲染

React 没有特殊的语法来编写条件语句,因此你使用的就是普通的 JavaScript 代码。例如使用 if 语句根据条件引入 JSX

let content;
if (isLoggedIn) {
  content = <AdminPanel />;
} else {
  content = <LoginForm />;
}
return (
  <div>
    {content}
  </div>
);

// 条件 ?运算符
<div>
  {isLoggedIn ? (
    <AdminPanel />
  ) : (
    <LoginForm />
  )}
</div>

// 逻辑 && 语法
<div>
  {isLoggedIn && <AdminPanel />}
</div>
6. 渲染列表

注意, 必须设置 key 属性。类同vue中的 v-for中的 key

const products = [{id:1,title:"name1"},{id:2,title:"name2"}]

return (
  <ul>{
    products.map(product =>
     <li key={product.id}>
      {product.title}
     </li>
    )}
   </ul>
);
7. 响应事件

注意,onClick={handleClick} 的结尾没有小括号!不要 调用 事件处理函数:你只需 把函数传递给事件 即可。当用户点击按钮时 React 会调用你传递的事件处理函数

function MyButton() {
  function handleClick() {
    alert('You clicked me!');
  }

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );
}
8. 更新界面

useState(),类似与vue3中ref(),reactive()等,创建响应式数据,数据改变时会更新到界面

当React重新渲染一个组件时:

  • React 会再次调用你的函数
  • 函数会返回新的 JSX 快照
  • React 会更新界面以匹配返回的快照
import { useState } from 'react';

export default function MyApp() {
  return (
    <div>
      <h1>Counters that update separately</h1>
      <MyButton />
      <MyButton />
    </div>
  );
}

function MyButton() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      Clicked {count} times
    </button>
  );
}
9. 使用Hook

以use开头的函数被称为Hook。useState 是React提供的一个内置Hook。可以通过组合现有Hook来编写自己的Hook。

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

10. 组件间共享数据

变量上移至父组件,通过prop传递

export default function MyApp() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <h1>Counters that update together</h1>
      <MyButton count={count} onClick={handleClick} />
      <MyButton count={count} onClick={handleClick} />
    </div>
  );
}
function MyButton({ count, onClick }) {
  return (
    <button onClick={onClick}>
      Clicked {count} times
    </button>
  );
}
11. 构建state 准则

当你编写一个存有 state 的组件时,你需要选择使用多少个 state 变量以及它们都是怎样的数据格式。尽管选择次优的 state 结构下也可以编写正确的程序,但有几个原则可以指导您做出更好的决策:

  1. 合并关联的 state。如果你总是同时更新两个或更多的 state 变量,请考虑将它们合并为一个单独的 state 变量。
  2. 避免互相矛盾的 state。当 state 结构中存在多个相互矛盾或“不一致”的 state 时,你就可能为此会留下隐患。应尽量避免这种情况。
  3. 避免冗余的 state。如果你能在渲染期间从组件的 props 或其现有的 state 变量中计算出一些信息,则不应将这些信息放入该组件的 state 中。
  4. 避免重复的 state。当同一数据在多个 state 变量之间或在多个嵌套对象中重复时,这会很难保持它们同步。应尽可能减少重复。
  5. 避免深度嵌套的 state。深度分层的 state 更新起来不是很方便。如果可能的话,最好以扁平化方式构建 state。

安装

1. 启动一个新的React项目
基础脚手架
  • npx create-react-app
全栈架构
  1. Next.js npx create-next-app@latest
  2. Remix npx create-remix

Next.js 的 App Router 是对 Next.js API 的重新设计,旨在实现 React 团队的全栈架构愿景。它让你在异步组件中获取数据,这些组件甚至能在服务端构建过程中运行。

React官方与Next.js团队合作,研究、开发、集成和测试与框架无关的 React 前沿功能

2. 使用TypeScript

TypeScript 天然支持 JSX——只需在项目中添加 @types/react@types/react-dom 即可获得完整的 React Web 支持

npm install @types/react @types/react-dom

内置Hook

Hook 可以帮助在组件中使用不同的 React 功能。你可以使用内置的 Hook 或使用自定义 Hook

State Hook
Context Hook

上下文帮助组件 从祖先组件接收信息,而无需将其作为 props 传递

使用useContext读取订阅上下文

function Button(){
  const theme = useContext(ThemeContext);
  // ...
}
Ref Hook

ref 允许组件 保存一些不用于渲染的信息,比如 DOM 节点或 timeout ID。与状态不同,更新 ref 不会重新渲染组件。ref 是从 React 范例中的“脱围机制”。当需要与非 React 系统如浏览器内置 API 一同工作时,ref 将会非常有用。

  • 使用 useRef 声明 ref。你可以在其中保存任何值,但最常用于保存 DOM 节点。
  • 使用 useImperativeHandle 自定义从组件中暴露的 ref,但是很少使用。
const iptRef = useRef(null);
const timer = useRef(null);
useEffect(()=>{
  iptRef.current.focus();
  timer.current = setInterval(()=>{
      todo();
  },100);
  return ()=>{
    clearInterval(timer.current);
  }
},[])
return (<>
  <input ref={inputRef}/>
</>)
Effect Hook

处理网络、浏览器、DOM、动画、使用不同 UI 库编写的小部件以及其他非 React 代码。

  • 使用 useEffect 将组件连接到外部系统。
function CardList(){
  const [list,setList] = useState<Array<{id:string;title:string}>>([]);
  const [page,setPage] = useState(0);
  useEffect((
    // 第二个参数不存在 或者为空时 组件初始化完成 执行该函数
    axios.get().then((res)=>{
        todo...
    })
    return ()=>{
      // 组件卸载时 执行该函数
    }
  ),[])
  useEffect(()=>{
      // page变化时 执行该函数
  },[page])
  return <ol>
     {
        list.map((item)=>{
           return (<li key={item.id}>{item.title}</li>)
        })
     }
   </ol>
}


  • useLayoutEffect 在浏览器重新绘制屏幕前执行,可以在此处测量布局。 (较少使用)
  • useInsertionEffect 在 React 对 DOM 进行更改之前触发,库可以在此处插入动态 CSS。(较少使用)
性能Hook

可以使用以下 Hook 跳过计算和不必要的重新渲染:

  • 使用 useMemo 缓存计算代价昂贵的计算结果。
  • 使用 useCallback 将函数传递给优化组件之前缓存函数定义。

当屏幕确实需要更新,无法跳过重新渲染。在这种情况下,可以通过将必须同步的阻塞更新(比如使用输入法输入内容)与不需要阻塞用户界面的非阻塞更新(比如更新图表)分离以提高性能。

  • useTransition 允许将状态转换标记为非阻塞,并允许其他更新中断它。
  • useDeferredValue 允许延迟更新 UI 的非关键部分,以让其他部分先更新。
资源Hook

use(resource) 是一个 React Hook,它可以让你读取类似于 Promisecontext 的资源的值。

与其他Hook不同,它可以在循环和条件语句中调用. 但是调用use的函数必须是一个组件或Hook

注意: use(Promise) ,当promise处于pendding时,整个组件或者Hook都会挂起,直到resolve后,重新执行组件或者hook. 而async/await 则不同,仅在await处pending, resolve后从await处继续执行.

  • context
import { createContext, use } from 'react';

const ThemeContext = createContext(null);

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}

function Form() {
  return (
    <Panel title="Welcome">
      <Button show={true}>Sign up</Button>
      <Button show={false}>Log in</Button>
    </Panel>
  );
}

function Panel({ title, children }) {
  const theme = use(ThemeContext);
  const className = 'panel-' + theme;
  return (
    <section className={className}>
      <h1>{title}</h1>
      {children}
    </section>
  )
}

function Button({ show, children }) {
  if (show) {
    const theme = use(ThemeContext);
    const className = 'button-' + theme;
    return (
      <button className={className}>
        {children}
      </button>
    );
  }
  return false
}
  • promise

reject时需要使用错误边界处理

import React, { ErrorBoundary, Suspense, use } from "react"; 
export function User ({ getUser}) {
  return (
    <ErrorBoundary fallback={<p>catch error...</p>}>
      <Suspense fallback={<p>loading...</p>}>
        <Message getUser={getUser} />
      </Suspense>
    </ErrorBoundary>
  );
}
function getUser = axios.get("");
function Message({ getUser}) {
  const content = use(getUser);
  return <p>user: {content}</p>;
}
useReducer

常用内置组件

Fragment

<Fragment>通常使用<>...</>替代,它们都允许你在不添加额外节点的情况下将子元素组合.

注意:

  1. 如果你要传递 key 给一个 <Fragment>,你不能使用 <>...</>,你必须从 'react' 中导入 Fragment 且表示为<Fragment key={yourKey}>...</Fragment>
  2. 当你要从 <><Child /></> 转换为 [<Child />]<><Child /></> 转换为 <Child />,React 并不会重置 state。这个规则只在一层深度的情况下生效,如果从 <><><Child /></></> 转换为 <Child /> 则会重置 state。在这里查看更详细的介绍。
Suspense
<Suspense fallback={<Loading />}>
  {/* 当SomeComponent未加载完成时,渲染Loading组件 */}
  <SomeComponent />
</Suspense>
  • children:真正的 UI 渲染内容。如果 children 在渲染中被挂起,Suspense 边界将会渲染 fallback
  • fallback:真正的 UI 未渲染完成时代替其渲染的备用 UI,它可以是任何有效的 React 节点。后备方案通常是一个轻量的占位符,例如表示加载中的图标或者骨架屏。当 children 被挂起时,Suspense 将自动切换至渲染 fallback;当数据准备好时,又会自动切换至渲染 children。如果 fallback 在渲染中被挂起,那么将自动激活最近的 Suspense 边界。
  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值