react query 学习笔记

文章目录

  • react query 学习笔记
    • 查询客户端 QueryClient
      • 获取查询客户端 useQueryClient
      • 异步重新请求数据 queryClient.fetchQuery /
      • 使查询失效 queryClient.invalidateQueries 与 重新请求数据queryClient.refetchQueries
    • 查询 Queries
      • useQuery查询配置对象
        • 查询的键值 Query Keys
        • 查询函数Query Functions
        • 初始化的查询数据(查询数据占位符) initialData 与 placeholderData
      • useQuery的返回值
      • 分页查询 +keepPreviousData
    • 修改 useMutation
      • useMutation配置对象
        • 场景:修改数据之后,需要刷新数据
        • 乐观更新与状态回滚
      • useMutation的返回值对象
        • 触发mutationFn请求的属性mutate与mutateAsync
    • 过滤器 Filters
      • 查询过滤器 QueryFilters

react query 学习笔记

react query的一些概念理解

  • 默认情况下,通过useQueryuseInfiniteQuery生成的查询实例会将缓存的数据视为过时(stale)的。

    • 理解1:这里的数据都被称为缓存数据(都会被保存在内存中),只不过区分为新鲜(fresh)数据过时(stale)数据,通过设置staleTime来区分新鲜数据和过时数据。
    • 理解2:新鲜数据与过时数据的作用是重新向后端发送请求时是否真的会请求后端。如果该查询的缓存状态是stale(老旧),表示该查询将会有资格重新请求后端接口,但如果查询的缓存状态是fresh(最新)的,该查询不会请求后端接口直接采用缓存数据。
    • 理解3:useQueryuseInfiniteQuery返回的实例被称为查询实例
  • 出现以下情况时,过时的查询(缓存过时)会在后台自动重新获取数据

    • ①挂载新的查询实例(很好理解创建一个新实例)。发生场景:当组件首次加载,将会触发数据的获取。如果组件被卸载后再次被加载,此时也会触发数据的重新获取。
    • ②窗口重新聚焦。
    • ③网络重新连接
    • ④该查询可选地配置有重新获取数据的间隔(refetch interval),设置定时刷新。
    • 查询键被改变时,将会自动触发数据的重新获取。(react-query会进行深度比对)
  • 当查询结果不再具有useQuery,useInfiniteQuery或查询观察者(query observers)的活动实例(active instances)时( 感觉意思是当前网页没有使用到的查询实例??),该查询结果将被标记为inactive(不活跃)。在缓存状态处于inactive状态或者使用这个查询数据的组件卸载时,超过5分钟(默认情况下)后,react-query将会自动清除该缓存。

    • 理解1:当在缓存中删除查询数据后,此时的表现和这个查询数据从未加载过一样。
    • 理解2:缓存数据的第二对状态,不活跃状态活跃状态,这个状态影响的是react-query是否清除查询请求。(暂时不清楚清不清除有什么区分,猜测是否在开发调试工具中可以观测)

版本是react query 5 , 只记录工作中使用到的主要功能,在使用中会不断更新。
阅读文章:https://juejin.cn/post/7202945024748912699
react query文档:https://cangsdarm.github.io/react-query-web-i18n/react/
react query文档的简单翻译版:https://juejin.cn/post/7123119750523125796

查询客户端 QueryClient

作用:①管理缓存数据,

import { QueryClient } from '@tanstack/react-query'

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: Infinity,
    },
  },
})

需要将查询客户端queryClient 提供给全局App

import {
  QueryClient,
  QueryClientProvider,
} from "@tanstack/react-query";

// 创建一个 client
const queryClient = new QueryClient();

function App() {
  return (
    // 提供 client 至 App
    <QueryClientProvider client={queryClient}>
      <Todos />
    </QueryClientProvider>
  );
}

获取查询客户端 useQueryClient

在项目的组件中,也可以调用queryClient,使用useQueryClient钩子,就可以获取全局的查询客户端queryClient

import { useQueryClient } from '@tanstack/react-query'
const queryClient = useQueryClient();

queryClient对象的属性

用法语法描述同步或者异步返回值
获取缓存数据getQueryData(queryKey?: QueryKey,filters?: QueryFilters)获取现有查询的缓存数据,如果查询不存在,则返回undefined同步缓存的数据
获取请求的状态getQueryState(queryKey?: QueryKey,filters?: QueryFilters)获取现有查询的状态,如果查询不存在,则返回undefined同步状态对象
dataUpdatedAt: number属性:查询最近一次返回status"success"的时间戳

异步重新请求数据 queryClient.fetchQuery /

  • queryClient.fetchQuery({uery Keys,Query Function,other})异步请求数据,类似useQuery,可用于提取和缓存查询。
    在特殊场景下(如:强制触发查询等)可以使用queryClient.fetchQuery()请求数据。
    如果在缓存中有对应的数据(通过查询键匹配)且未过期,可以无需请求直接使用缓存数据。
    如果没有缓存或缓存已经过期,那么react-query会重新请求并且缓存数据。

使查询失效 queryClient.invalidateQueries 与 重新请求数据queryClient.refetchQueries

使查询失效 queryClient.invalidateQueries
queryClient.invalidateQueries(filters?: QueryFilters查询筛选器,options?: RefetchOptions):该方法使匹配到的查询失效。默认情况下,所有匹配的查询都会立即标记为无效,并且活动查询将在后台重新提取。

在这里插入图片描述

refetchType:active 默认值,活动查询重新提取
refetchType: 'none' 不会重新提取任何查询,仅将匹配查询标记为无效。
refetchType: 'all' 活动查询与非活动查询都会重新提取。

await queryClient.invalidateQueries(
  {
    queryKey: ['posts'],
    exact, // 关闭模糊查询
    //refetchType?: 'active' | 'inactive' | 'all' | 'none'
    refetchType: 'active', 
  },
  { throwOnError, cancelRefetch },
)

predicate()函数可以进行更细力度的匹配, 此函数将从查询缓存中接收每个Query 实例,并允许你返回 truefalse 来确定是否使该查询无效。

// 比如这个invalidateQueries,精确到参数version>10的请求
queryClient.invalidateQueries({
  predicate: (query) =>
    query.queryKey[0] === 'todos' && query.queryKey[1]?.version >= 10,
})

// 这个请求会被设置为过期
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 20 }],
  queryFn: fetchTodoList,
})

// 这个请求会被设置为过期
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 10 }],
  queryFn: fetchTodoList,
})

// 这个请求不会
const todoListQuery = useQuery({
  queryKey: ['todos', { version: 5 }],
  queryFn: fetchTodoList,
})

重新请求数据queryClient.refetchQueries
queryClient.refetchQueries(filters?: QueryFilters查询筛选器,options?: RefetchOptions):所有匹配(默认非活动和活动)的查询请求(查询键值是模糊匹配)都重新请求。

	// refetch all queries:
	await queryClient.refetchQueries()

	// refetch all stale queries:
	await queryClient.refetchQueries({ stale: true })

	// refetch all active queries partially matching a query key:
	await queryClient.refetchQueries({ queryKey: ['posts'], type: 'active' })

	// refetch all active queries exactly matching a query key:
	await queryClient.refetchQueries({
  		queryKey: ['posts', 1],
  		type: 'active',
  		exact: true,
	})

两者的区别

  • invalidateQueries只是将数据标记为过时,以便它们在下次观察者挂载时重新获取,refetchQueries会立刻重新获取数据,即使没有观察者也可以。对于具有活动观察者的查询,没有区别。
  • invalidateQueries有更细腻灵活的配置,可以精确到某些请求

查询 Queries

ReactQuery 会在全局维护一个服务端状态树,根据 Query key 去查找状态树中是否有可用的数据,如果有则直接返回,否则则会发起请求,并将请求结果以 Query key 为主键存储到状态树中。

订阅一个查询useQuery({配置对象}),通常包含两个参数:

  • 唯一标识这个请求的 Query keyReactQuery 的缓存策略是基于这个 key 来实现的,key变化缓存失效,请求重新发送。
  • 一个真正执行请求并返回数据的异步方法

查询的三个钩子

  • useQuery :发起单个请求
  • useQueries:发起多个请求
  • useInfiniteQuery:无限查询
const {
  data,
  dataUpdatedAt,
  error,
  errorUpdatedAt,
  failureCount,
  failureReason,
  fetchStatus,
  isError,
  isFetched,
  isFetchedAfterMount,
  isFetching,
  isInitialLoading,
  isLoading,
  isLoadingError,
  isPaused,
  isPending,
  isPlaceholderData,
  isRefetchError,
  isRefetching,
  isStale,
  isSuccess,
  refetch,
  status,
} = useQuery(
  {
    queryKey,
    queryFn,
    gcTime,
    enabled,
    networkMode,
    initialData,
    initialDataUpdatedAt,
    meta,
    notifyOnChangeProps,
    placeholderData,
    queryKeyHashFn,
    refetchInterval,
    refetchIntervalInBackground,
    refetchOnMount,
    refetchOnReconnect,
    refetchOnWindowFocus,
    retry,
    retryOnMount,
    retryDelay,
    select,
    staleTime,
    structuralSharing,
    throwOnError,
  },
  queryClient,
)

useQuery查询配置对象

描述
queryKey查询请求的key
queryFn查询请求的请求函数
enabled: boolean查询是否自动运行,是否可用,为false不会发起请求。
可以控制查询请求运行的时机(比如请求参数不为空时才发送查询请求param!==null)
也可以使用useQuery返回的refetch触发
staleTime: number | Infinit数据缓存的时长,单位是毫秒,默认为0。在时间范围内,再次发送请求时,直接使用缓存数据。
查询的键值 Query Keys

语法:queryKey:数组 要求数组可序列化,并且数组唯一。
作用:React Query 在内部基于查询键值来管理查询缓存,可以理解为依赖,如果依赖变化那么会重新发送查询请求。

import { useQuery} from "@tanstack/react-query";

function Todos({ todoId }) {{
  const result = useQuery({
    queryKey: ['todos', todoId],
    queryFn: () => fetchTodoById(todoId),
  });
}

案例1:查询键值序列化后,相同的会被去重。数组项的顺序影响序列化后的值,对象的key的顺序不影响序列化后的值

// 不管对象中键值的顺序如何,以下所有查询都被认为是相等的:
useQuery({ queryKey: ['todos', { status, page }], ... });
useQuery({ queryKey: ['todos', { page, status }], ...});
useQuery({ queryKey: ['todos', { page, status, other: undefined }], ... });

//以下查询键值不相等
useQuery({ queryKey: ['todos', status, page], ... });
useQuery({ queryKey: ['todos', page, status], ...});
useQuery({ queryKey: ['todos', undefined, page, status], ...});

案例2:如果你的查询功能依赖于变量,则将其包含在查询键值中

function Todos({ todoId }) {{
  const result = useQuery({
    queryKey: ['todos', todoId],
    queryFn: () => fetchTodoById(todoId),
  });
}
查询函数Query Functions

查询函数的参数
每一个查询函数的参数都是QueryFunctionContext对象,该对象中包含

  • queryKey: QueryKey: 查询键值
  • pageParam: unknown | undefined:只会在无限查询场景传递,为查询当前页所使用的参数
  • signal?: AbortSignal:可以用来做查询取消
  • meta?: Record<string, unknown>:一个可选字段,可以填写任意关于该查询的额外信息
function Todos({ status, page }) {
  const result = useQuery({
    queryKey: ["todos", { status, page }],
    queryFn: fetchTodoList,
  });
}

// 在查询函数中访问键值,状态和页面变量!
function fetchTodoList({ queryKey }) {
  const [_key, { status, page }] = queryKey;
  return new Promise();
}

查询函数的返回值
查询函数要求是返回Promise的函数(异步同步都可以),其该Promise最终状态会变成resolvedrejected

初始化的查询数据(查询数据占位符) initialData 与 placeholderData

使用场景:在应用的其他地方已经获取到了查询的初始数据或者自定义一个初始数据

属性保留在缓存描述
initialData
保留在缓存中,因此不建议为此选项提供占位符,部分或不完整的数据
初始化数据,一般用于已经有完整的数据但是不确定数据是否已经变更的场景
initialData 受staleTime影响,如果初始化数据没过时,就会一直使用初始化数据, 否则重新发起请求
placeholderData×
数据没有被持久化到缓存中,更倾向于预览的作用
在还未第一次请求到数据之前的这段时间,如果获取该查询的data,则会获取到placeholderData属性的值
一旦查询从后端获取到了数据,则placeholderData属性失效

placeholderData理解与使用
1.placeholderData类似于解构,如果解构项的值为undefined,将会采用设置的默认值


  {
const issuesQuery = useQuery(
	queryKey:["issues"], 
  	queryFn:fetch,
    placeholderData: [],
  }
)
const { data = [] } = useQuery(
	{
  	queryKey:["issues"], 
  	queryFn:fetch,
	}
)

2.当需要为用户提供假数据时,就可以使用placeholderData,比如在获取用户数据时,为了UI不那么难看,可以先默认展示一个占位头像。
3.如某个依赖查询,依赖了该数据需要使用isPlaceholderData属性来判断当前数据是否真实.

// 请求1
const userQuery = useQuery(
 {
  queryKey:["user"],
  queryFn:fetchUser,
 }
)
// 依赖请求1返回值的请求2
const userIssues = useQuery(
 {
  queryKey:["userIssues", userQuery.data.login],
  queryFn:fetchUserIssues,
  enabled: !userQuery.isPlaceholderData 
      && userQuery.data?.login,
  }
)

initialData理解与使用
1.使用案例

// 将立即显示 initialTodos,但在挂载后也将立即重新获取todos, initialData立即过期
const result = useQuery({
  queryKey: ["todos"],
  queryFn: () => fetch("/todos"),
  initialData: initialTodos,
});

// 使用之前的缓存信息:将 `todos` 查询中的某个 todo 用作此 todos 查询的初始数据
const result = useQuery({
  queryKey: ["todo", todoId],
  queryFn: () => fetch("/todos"),
  initialData: () => { 
    return queryClient.getQueryData(["todos"])?.find((d) => d.id === todoId);
  },
});

2.精准控制过期时间,过期时间 = initialDataUpdatedAt + staleTime
initialDataUpdatedAt:表示初始数据上一次更新的时间,可以与getQueryState钩子函数、staleTime配置属性精准控制initialData过期时间。
initialDataUpdatedAt类型为Number类型的 JS 时间戳(以毫秒为单位,如Date.now())

const issueDetailQuery = useQuery(
 {
  queryKey:["issue", repo, owner, issueNumber],
  queryFn:fetchIssue,
  staleTime: 1000 * 60,
  initialData: () => { // 初始数据的过期时间为getQueryData上一次刷新的时间+staleTime的时间
      const issues = queryClient.getQueryData(["issues", repo, owner])
      if (!issues) return undefined;
      const issue = issues.find(issue => issue.number === issueNumber)
      return issue;
    }, 
  initialDataUpdatedAt: () => { // 初始数据issue最后一次新时间dataUpdatedAt
      const {dataUpdatedAt} = queryClient.getQueryState(["issues", repo, owner])
      return dataUpdatedAt;
    }
  },
)

useQuery的返回值

useQuery返回值为包含所有关于该查询信息的对象

status告诉我们有关data的状态:有或者没有?

  • status :查询的状态,有正在加载、失败、成功三个状态
  • isLoading 或者 status === 'loading' :查询暂时还没有数据
  • isError 或者 status === 'error':查询出错
  • isSuccess 或者 status === 'success' 查询成功,并且数据可用

以下两个状态是获取查询函数queryFn的返回值(Promise的返回值而不是一个新的Promise)

  • error:如果查询处于isError状态,则可以通过error属性获取该错误
  • data :如果查询处于isSuccess状态,则可以通过data属性获得数据

fetchStatus告诉我们有关queryFn的状态:在执行还是没在执行?

  • fetchStatus === 'fetching' 正在查询中
  • fetchStatus === 'paused' 查询想要获取,但它被暂停了
  • fetchStatus === 'idle' 该查询处于闲置状态

为什么需要两个键来表示对象?
后台刷新和数据过期重试可以让一个请求处于多种情况。

一个state='success'的查询通常处于fetchStatus='idle'状态。但如果同时后台重新获取动作,该查询也可能为fetchStatus='fetching'状态。
一个没有数据的查询通常处于status='loading'状态和fetchStatus='loading'状态。如果同时无网络连接,该请求也可能为fetchStatus='paused'状态。

分页查询 +keepPreviousData

将分页的信息作为queryKey,当页数发生变化时会自动重新请求新数据。
存在问题:UI 在successloading状态之间来回跳转,因为每个新页面都被视为一个全新的查询。(感觉这样体现也正常?不是很理解,翻页不就是需要重新请求新数据吗?可能希望已经请求过的页数不在loading重新请求?)

const result = useQuery({
  queryKey: ["projects", page],
  queryFn: fetchProjects,
});

keepPreviousData:true的作用
1.请求新数据时,即使查询键值已更改,上次成功获取的数据仍可用
2.当新数据到达时,先前的数据将被无缝交换以显示新数据
3.可以使用isPreviousData来了解当前查询提供的是什么数据

function Todos() {
  const [page, setPage] = React.useState(0);

  const fetchProjects = (page = 0) =>
    fetch("/api/projects?page=" + page).then((res) => res.json());

  const { isLoading, isError, error, data, isFetching, isPreviousData } =
    useQuery({
      queryKey: ["projects", page],
      queryFn: () => fetchProjects(page),
      keepPreviousData: true,
    });

  return (
    <div>
      {isLoading ? (
        <div>Loading...</div>
      ) : isError ? (
        <div>Error: {error.message}</div>
      ) : (
        <div>
          {data.projects.map((project) => (
            <p key={project.id}>{project.name}</p>
          ))}
        </div>
      )}
      <span>Current Page: {page + 1}</span>
      <button
        onClick={() => setPage((old) => Math.max(old - 1, 0))}
        disabled={page === 0}
      >
        Previous Page
      </button>{" "}
      <button
        onClick={() => {
          if (!isPreviousData && data.hasMore) {
            setPage((old) => old + 1);
          }
        }}
        // 禁用跳转下一页的按钮,直到我们知道下一页数据是可用的
        disabled={isPreviousData || !data?.hasMore}
      >
        Next Page
      </button>
      {isFetching ? <span> Loading...</span> : null}{" "}
    </div>
  );
}

修改 useMutation

说明:react-query中使用useMutation向后端发送创建/更新/删除操作
mutationFn的调用时机:useMutation钩子不会在组件加载时就直接请求,需要手动调用mutate方法并传入请求参数才会生效。

const {
  data,
  error,
  isError,
  isIdle,
  isPending,
  isPaused,
  isSuccess,
  failureCount,
  failureReason,
  mutate,
  mutateAsync,
  reset,
  status,
  submittedAt,
  variables,
} = useMutation({
  mutationFn,
  gcTime,
  mutationKey,
  networkMode,
  onError,
  onMutate,
  onSettled,
  onSuccess,
  retry,
  retryDelay,
  throwOnError,
  meta,
})

使用案例:添加一个新todo

function App() {
  const mutation = useMutation({
    mutationFn: (newTodo) => {
      return axios.post("/todos", newTodo);
    },
  });

  return (
    <div>
      {mutation.isLoading ? (
        "Adding todo..."
      ) : (
        <>
          {mutation.isError ? (
            <div>An error occurred: {mutation.error.message}</div>
          ) : null}

          {mutation.isSuccess ? <div>Todo added!</div> : null}

          <button
            onClick={() => {
              mutation.mutate({ id: new Date(), title: "Do Laundry" });
            }}
          >
            Create Todo
          </button>
        </>
      )}
    </div>
  );
}

useMutation配置对象

属性描述
mutationFn: (variables: TVariables) => Promise必选:执行异步任务并返回承诺的函数,参数variables是一个mutate传递给mutationFn的对象
onSuccess: (data: TData, variables: TVariables, context: TContext) => Promise<unknown> | unknown第一个参数是mutationFn函数的返回值,第二个参数是mutate函数传递的参数
onError: (err: TError, variables: TVariables, context?: TContext) => Promise<0unknown> | unknown失败的回调函数
onSettled: (data: TData, error: TError, variables: TVariables, context?: TContext) => Promise<unknown> | unknown不管请求成功还是失败都会执行
reset: () => void将突变重置为初始状态
场景:修改数据之后,需要刷新数据

在很多场景中,我们希望一个数据修改成功后,涉及该数据的相关查询都重新获取最新的数据

案例1
当对postTodo的修改成功时,我们可能希望对所有的todos查询都暂时失效,然后重新获取以显示新的 todo 项。

import { useMutation, useQueryClient } from "@tanstack/react-query";

const queryClient = useQueryClient();

// 当此修改成功时,将所有带有`todos`和`reminders`查询键值的查询都无效
const mutation = useMutation({
  mutationFn: addTodo,
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ["todos"] });
  },
});
乐观更新与状态回滚

在执行修改之前,当你"乐观"地打算进行更新时,修改有可能失败(可能性非零)。
①大多数情况下,让查询触发重新获取,使其恢复到真正的和服务器一致的状态。
②还有一种方式,是进行状态回滚

useMutationonMutate 回调允许返回一个特定值,该值将作为最后一个参数传递给 onErroronSettled 处理 – 在大多数情况下,以这种方式来传递一个回滚函数是最有用的。

onMutate: (variables: TVariables) => Promise<TContext | void> | TContext | void :将在触发突变函数之前触发,同时也会接受传递给突变函数的参数

案例:添加新的todo时更新todos列表

const queryClient = useQueryClient();

useMutation({
  mutationFn: updateTodo,
  // 当 mutate 调用时
  onMutate: async (newTodo) => {
    // 撤销相关的查询(这样它们就不会覆盖我们的乐观更新)
    await queryClient.cancelQueries(["todos"]);

    // 保存前一次状态的快照
    const previousTodos = queryClient.getQueryData(["todos"]);

    // 执行"乐观"更新
    queryClient.setQueryData(["todos"], (old) => [...old, newTodo]);

    // 返回具有快照值的上下文对象
    return { previousTodos };
  },
  // 如果修改失败,则使用 onMutate 返回的上下文进行回滚
  onError: (err, newTodo, context) => {
    queryClient.setQueryData(["todos"], context.previousTodos);
  },
  // 总是在错误或成功之后重新获取:
  onSettled: () => {
    queryClient.invalidateQueries("todos");
  },
});

useMutation的返回值对象

触发mutationFn请求的属性mutate与mutateAsync
  • useMutation返回值对象.mutate:同步触发
  • useMutation返回值对象.mutateAsync:异步触发
mutate(variables, {
  onError,
  onSettled,
  onSuccess,
})

过滤器 Filters

某些方法可以接受查询过滤QueryFilters 或者修改过滤 MutationFilters 对象。

// 取消所有查询
await queryClient.cancelQueries();

// 删除所有以`posts`开头的键值的非活跃的查询
queryClient.removeQueries({ queryKey: ["posts"], type: "inactive" });

// 重新获取所有活跃的查询
await queryClient.refetchQueries({ type: 'active' })

// 重新获取键中以`posts`开头的所有活跃的查询
await queryClient.refetchQueries({ queryKey: ['posts'], type: 'active' })

查询过滤器 QueryFilters

属性名描述
queryKey?: QueryKey设置此属性以定义要匹配的查询键值,默认匹配的规则是以queryKey开头的查询(模糊查询)。
exact?: boolean是否关闭模糊查询,默认是false
type?: ‘active’ | ‘inactive’ | ‘all’默认为all
active表示匹配活跃查询
inactive表示匹配非活跃的查询
stale?: booleantrue表示当前过时(staled)的
false表示匹配当前没过时(fresh)的
fetchStatus?: FetchStatusfetching 匹配当前正在获取的
paused匹配当前想要获取但被暂停了的
idle配当前未在获取的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/542653.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LLM生成模型在生物基因DNA应用:HyenaDNA

参考&#xff1a; https://github.com/HazyResearch/hyena-dna 整体框架基本就是GPT模型架构 不一样的就是&#x1d5a7;&#x1d5d2;&#x1d5be;&#x1d5c7;&#x1d5ba;&#x1d5a3;&#x1d5ad;&#x1d5a0; block &#xff0c;主要是GPT的多重自注意力层引入了cnn…

深度学习图像处理基础工具——opencv 实战信用卡数字识别

任务 信用卡数字识别 穿插之前学的知识点 形态学操作 模板匹配 等 总体流程与方法 1.有一个模板 2 用轮廓检测把模板中数字拿出来 外接矩形&#xff08;模板和输入图像的大小要一致 &#xff09;3 一系列预处理操作 问题的解决思路 1.分析准备&#xff1a;准备模板&#…

微信小程序兼容iphone适配安全区域

背景&#xff1a; 小程序页面底部在ios中会有小黑条遮挡 上代码&#xff1a; padding-bottom: constant(safe-area-inset-bottom); /* 兼容 iOS < 11.2 */ padding-bottom: env(safe-area-inset-bottom); /* 兼容 iOS > 11.2 */ 项目描述&#xff1a; 微信小程序是通过…

中国绿色技术助力全球能源转型(国际论坛)

中国的清洁能源发展战略和实践对全球能源结构转型产生了深远影响。作为全球最大的可再生能源生产和消费国&#xff0c;中国在推动国内可再生能源产业发展的同时&#xff0c;也积极与世界各国分享技术和经验&#xff0c;促进全球范围内清洁能源技术的普及和应用成本的降低。例如…

FL Studio808鼓音在哪 FL Studio怎么让音乐鼓点更有力 FL Studio教程

FL Studio808鼓音在哪&#xff1f;808是一款电鼓机的名称&#xff0c;它发出的声音也被称之为808鼓&#xff0c;通常我们可以安装鼓机插件来使用&#xff0c;但FL Studio中自带的也有808鼓的采样音频。FL Studio怎么让音乐鼓点更有力&#xff1f;让鼓点更有力要从EQ均衡器、压缩…

ELK、ELKF企业级日志分析系统介绍

前言 随着企业级应用系统日益复杂&#xff0c;随之产生的海量日志数据。传统的日志管理和分析手段&#xff0c;难以做到高效检索、实时监控以及深度挖掘潜在价值。在此背景下&#xff0c;ELK日志分析系统应运而生。"Elastic" 是指 Elastic 公司所提供的一系列与搜索…

在 Google Cloud 上轻松部署开放大语言模型

今天&#xff0c;“在 Google Cloud 上部署”功能正式上线&#xff01; 这是 Hugging Face Hub 上的一个新功能&#xff0c;让开发者可以轻松地将数千个基础模型使用 Vertex AI 或 Google Kubernetes Engine (GKE) 部署到 Google Cloud。 Model Garden (模型库) 是 Google Clou…

AI大模型探索之路-实战篇:基于CVP架构-企业级知识库实战落地

目录 前言 一、概述 二、本地知识库需求分析 1. 知识库场景分析 2. 知识库应用特点 3. 知识库核心功能 三、本地知识库架构设计 1. RAG架构分析 2. 大模型方案选型 3. 应用技术架构选型 4. 向量数据库选型 5. 模型选型 三、本地知识库RAG评估 四、本地知识库代码落地 1. 文件…

CSS文本单行溢出和多行溢出样式

一、单行溢出 1.代码 <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>demo</title><style>#div2{overflow: hidden;white-space: nowrap;/*强制不换行*/text-overflow:ellipsis;/*超出的部分用省略号代替*…

一起学习python——基础篇(19)

今天来说一下python的如何修改文件名称、获取文件大小、读取文中指定的某一行内容。 1、修改文件名称&#xff1a; import os testPath"D:/pythonFile/test.txt" testPath2"D:/pythonFile/test2.txt" #修改文件名称使用rename方法&#xff0c; #第一个参…

Mac环境 llamafile 部署大语言模型LLM

文章目录 Github官网本地部署 llamafile 是一种可在你自己的电脑上运行的可执行大型语言模型&#xff08;LLM&#xff09;&#xff0c;它包含了给定的开放 LLM 的权重&#xff0c;以及运行该模型所需的一切。让人惊喜的是&#xff0c;你无需进行任何安装或配置。 Github https…

CSS核心样式-04-定位属性+轮播图静态结构布局案例

目录 十、定位属性 概念 定位属性 position 偏移量属性 1. 相对定位 性质 注意事项 实际应用 应用1&#xff1a;导航栏位置微调 应用2&#xff1a;文字位置微调 2. 绝对定位 绝对定位的性质 注意事项 为参考元素的参考点 祖先级为参考元素 祖先元素参考点 3. 固定…

【150套】基于SSM框架的Java毕业设计开发实战项目(附源码+演示视频+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f9e1;今天给大家分享150的Java毕业设计&#xff0c;基于ssm框架&#xff0c;这些项目都经过精心挑选&#xff0c;涵盖了不同的实战主题和用例&#xff0c;可做毕业设计和课程…

数据库SQL语言实战(一)

目录 创建SQL表 题目一 题目二 题目三 插入数据 题目一 题目二 题目三 总结 创建SQL表 题目一 创建学生信息表&#xff08;学生编号、姓名、性别、年龄、出生日期、院系名称、班级&#xff09;&#xff1a; test1_student&#xff1a;sid char 12 not null、nam…

C语言入门(第一天:基础语法)

一、 使用工具 1、我们学习C语言所用的编辑器是Vscode&#xff0c;大家应该都不陌生了&#xff0c;但是要在编辑器内部编写C语言&#xff0c;我们需要下载安装一些工具插件来运行C语言。 有了以上两个工具就可以进行我们的C语言编译学习了&#xff01; 二、基础语法 1.第一个…

【opencv】示例-epipolar_lines.cpp 对极线

这段代码总的功能是使用OpenCV库进行立体视觉的估计。它从命令行读取两个图像文件名&#xff0c;使用SIFT算法检测关键点并计算这些点的描述子&#xff0c;接着通过FLANN库进行快速近似最近邻搜索来找到匹配的关键点。然后使用RANSAC方法计算基础矩阵&#xff0c;找到内点&…

Python学习笔记15 - 字符串

字符串是一个不可变的字符序列&#xff0c;另一个不可变的序列是元组 字符串的驻留机制 字符串的常用操作 字符串的查询 字符串的大小写转换 字符串内容 对齐操作的方法 字符串的劈分操作 字符串的判断 字符串替换 字符串合并 字符串的比较 字符串的切片 格式化字符串 字符串…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之三 简单动态聚光灯效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之三 简单动态聚光灯效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之三 简单动态聚光灯效果 一、简单介绍 二、简单动态聚光灯效果实现原理 三、简单动态聚光灯效果…

JVM、maven、Nexus

一、jvm简介 1.应用程序申请内存时出现的三种情况&#xff1a; ①OOM:内存溢出&#xff0c;是指应用系统中存在无法回收的内存或使用的内存过多&#xff0c;最终使得程序运行要用到的内存大于能提供的最大内存。此时程序就运行不了&#xff0c;系统会提示内存溢出&#xff0c…

GPT4.5发布了?OpenAI终于发布正式版Turbo,重回AI王座第一

令人惊讶的是&#xff0c;短短三个月内&#xff0c;全球最强AI的称号又一次易主了&#xff01;几个月前&#xff0c;Claude3 Opus的性能全面超过了GPT-4&#xff0c;全球网友纷纷转向Claude3&#xff0c;并分享了他们对Claude3的惊艳体验。然而&#xff0c;OpenAI最近再次展示了…