React04-Hooks 详解

news2024/12/28 21:02:52

一、Hooks

1. Hooks 简介

Hooks,可以翻译成钩子。

在类组件中钩子函数就是生命周期函数,Hooks 主要用在函数组件。

在 react 中定义组件有2种方式:class 定义的类组件和 function 定义的函数组件。

在类组件中,钩子函数可以给组件增加额外的功能。

类组件的不足:

  • 在一个钩子里可能有很多业务代码。
  • 一个业务很可能出现在多个钩子里。
  • class 组件中的 this 指向问题

在函数组件中,函数在执行完毕之后,会自动销毁内存,存储在函数中的状态无法保留。为了增加函数组件的功能,我们需要引入 Hooks。

类组件通过在构造器中直接使用 this.state = {} 给组件设置状态值,而函数组件不行。因为函数执行完后会销毁内容,在函数内声明的变量就会自定销毁,所以函数组件无法设置状态,于是 react 提供了 Hooks。

2. Hooks 的分类

Hook 分为2种,基础 Hook 和额外的 Hook。

基础 Hook:

  • useState
  • useEffect
  • useContext

额外的 Hook:

  • useReducer
  • useCallback
  • useMemo
  • useRef

所有 Hook 都以 use 开头。

3. Hook 的使用

 所有 Hook 都在 react 模块下,使用时需进行引入。

import { useState } from 'react';

二、useState

1. 使用 useState 的注意事项

(1) useState 向组件引入新的状态,这个状态会被保留在 react 中。

(2) useState 只有一个参数,这个参数是初始状态值,它可以是任意类型。

(3) useState 可以多次调用,意味着可以为组件传入多个状态。

(4) useState 返回值是一个数组,第一个元素就是我们定义的 state,第二个元素就是修改这个 state 的方法。接收 useState 的返回值使用数组结构语法,我们可以随意为 state 起名字。修改 state 的方法必须是 set + 状态名首字母大写构成,不按照约定写就会报错。

(5) useState 的参数也可以是一个函数,这个函数的返回值就是我们的初始状态。

2. 计数器案例

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <h3>{count}</h3>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  );
}

在这个案例中,我们定义了一个状态 count,传入的参数为函数 () => 1,则 count 的初始值为函数的返回值1。

当点击按钮时,调用修改方法 setCount 将 count 的值自增1,页面上计数器也会同步自增1。

3. 修改状态方法

修改状态的方法 set + 状态变量名:

  • 这个方法的参数可以是值(替换方法),也可以是一个函数。如果是函数,那么这个函数的参数就是初始状态值,这个方法就是更新方法。
  • 这个方法是异步的。

看如下案例:

function Counter() {
  const [count, setCount] = useState(() => 1);
  function handleCount(a) {
    setCount(a + 1);
    document.title = a;
  }
  return (
    <div>
      <h3>{count}</h3>
      <button onClick={() => handleCount(count)}>+</button>
    </div>
  );
}

在点击按钮后,计数器显示数字变为了2,但页面的标题还是1。每次点击按钮后,页面的标题都比计数器显示数字少1。因此执行代码先执行了第5行的设置页面标题,才执行第4行的设置 count 值,看过上篇文章就很容易理解。

三、useEffect

1. useEffect 简介

useEffect 这个 Hook 函数的主要作用就是将副作用代码添加到函数组件内。所谓的副作用代码就是 dom 更改、计时器、数据请求等。

使用场景:

  • useEffect(() => {}) 这种写法代表两个生命周期函数 componentDidMount 和 componentDidUpdate。
  • useEffect(() => {}, []) 这种写法代表生命周期函数 componentDidMount。
  • useEffect(() => () => {}) 这种写法代表组件卸载之前 componentWillUnmount 和 componentDidUpdate 两个生命周期函数。

2. useEffect(() => {})

useEffect 钩子函数传入一个函数作为参数,代表组件在加载完成后和数据更新时都会调用传入的函数。

function Counter() {
  const [count, setCount] = useState(() => 1);
  function handleCount(a) {
    setCount(a + 1);
    document.title = a;
  }
  useEffect(() => {
    console.log('hahaha');
  });
  return (
    <div>
      <h3>{count}</h3>
      <button onClick={() => handleCount(count)}>+</button>
    </div>
  );
}

在页面加载完成和每次点击按钮让计数器自增后,控制台都会打印 hahaha。即 useEffect Hook 实现了生命周期函数 componentDidMount 和 componentDidUpdate 的功能。

3. useEffect(() => {}, [])

useEffect 钩子函数传入一个函数和一个数组作为参数,代表组件在加载完成后会调用传入的函数。

function Counter() {
  const [count, setCount] = useState(() => 1);
  function handleCount(a) {
    setCount(a + 1);
    document.title = a;
  }
  useEffect(() => {
    console.log('hahaha');
  }, []);
  return (
    <div>
      <h3>{count}</h3>
      <button onClick={() => handleCount(count)}>+</button>
    </div>
  );
}

这个案例和上一个案例不同之处在于 useEffect 钩子函数传入了一个空数组作为第2个参数,当页面加载完成时控制台会打印 hahaha,点击按钮更新计数器后不再打印,即实现了生命周期函数 componentDidMount 的功能。

4. useEffect(() => () => {})

useEffect 钩子函数传入一个返回函数的函数作为参数,代表组件在数据更新时和卸载时会调用返回的函数。

function Counter(props) {
  const [count, setCount] = useState(() => 1);
  function handleCount(a) {
    setCount(a + 1);
    document.title = a;
  }
  useEffect(() => () => {
    console.log('hahaha');
  }, []);
  return (
    <div>
      <h3>{count}</h3>
      <button onClick={() => handleCount(count)}>+</button>
      <button onClick={() => props.root.unmount()}>卸载组件</button>
    </div>
  );
}

这个案例中,点击按钮更新计数器和点击卸载组件时控制台都会打印 hahaha,即实现了生命周期函数 componentWillUnmount 和 componentDidUpdate 的功能。

5. useEffect 第二个参数的使用

useEffect 钩子函数的第二个参数,正常添加空数组,代表的生命周期是 componentDidMount。即使我们修改了 state,useEffect 也只会调用一次。

如果我们想让某个 state 发生改变的时候,继续调用 useEffect,就需要把这个状态添加到第二个参数的数组中。

看下面的案例:

function Counter() {
  const [count, setCount] = useState(() => 1);
  const [person, setPerson] = useState({ name: 'zhangsan' });
  function handleCount(a) {
    setCount(a + 1);
    document.title = a;
  }
  useEffect(() => {
    console.log('计数器改变');
  }, [count]); // count 一旦发生改变,就会执行 useEffect
  return (
    <div>
      <h3>{count}</h3>
      <h3>{person.name}</h3>
      <button onClick={() => handleCount(count)}>+</button>
      <button onClick={() => setPerson({ name: 'lisi' })}>更改person</button>
    </div>
  );
}

useEffect 第二个参数传递了 count,那么将会在 count 状态更新时才会执行传入的函数。

6. useEffect 的异步处理

看下面的案例:

function Counter() {
  function asyncFn() {
    setTimeout(() => {
      console.log('hahaha');
    }, 1000);
  }
  useEffect(() => {
    asyncFn();
  });
  return (
    <div>
    </div>
  );
}

我们声明了一个异步函数,然后在 useEffect 中调用,预览正常,在页面加载完成1秒后打印 hahaha。

当我们使用 async/await 时,像下面这样:

function Counter() {
  function asyncFn() {
    setTimeout(() => {
      console.log('hahaha');
    }, 1000);
  }
  useEffect(async () => {
    await asyncFn();
  });
  return (
    <div>
    </div>
  );
}

这时控制台就会报一个警告:

在 useEffect 中如果使用了异步函数,那就需要定义一个自调用函数。如:

function Counter() {
  function asyncFn() {
    setTimeout(() => {
      console.log('hahaha');
    }, 1000);
  }
  useEffect(() => {
    (async () => {
      await asyncFn();
    })();
  });
  return (
    <div>
    </div>
  );
}

这时控制台就不报警告了。

遇到异步函数,我们需要在 useEffect 中添加一个自调用函数。

四、useContext

useContext 用于父组件向子孙组件传递数据,不需要再使用通过 props 从父组件向子组件逐级传递数据。

如果组件多层嵌套,使用 props 来传值显得极其复杂,这时就需要使用 useContext。

1. 引入 useContext

要使用 useContext,需要引入 useContext 和 createContext 两个函数。

import { useContext, createContext } from 'react';

2. 使用方法

首先定义一个 context 变量,用于存放当前上下文对象。将上下文对象的 Provider 作为父组件,通过 value 属性将要传递的值传给子孙组件。在子孙组件中就可以通过 useContext 获取到要传递的值。

const myContext = createContext(); // 当前上下文对象

function App() {
  const value = useContext(myContext);
  return (
    <div>{value}</div>
  );
}

export default function () {
  return (
    <myContext.Provider value={100}>
      <div>hello world</div>
      <App />
    </myContext.Provider>
  );
}

在 App 组件中我们获取到了父组件通过 context 传递来的 value 值。

五、useReducer

1. useReducer 简介

useReducer 是 useState 的替代方案。

对于拥有许多状态更新逻辑的组件来说,过于分散的事件处理程序可能会令人不知所措。对于这种情况,我们可以将组件的所有状态更新逻辑整合到一个外部函数中,这个函数叫作 reducer。

Reducer 是处理状态的另一种方式。可以通过三个步骤将 useState 迁移到 useReducer:

(1) 将设置状态的逻辑修改成 dispatch 的一个 action;
(2) 编写 一个 reducer 函数;
(3) 在组件中 使用 reducer。

使用 reducers 管理状态与直接设置状态略有不同。它不是通过设置状态来告诉 react “要做什么”,而是通过事件处理程序 dispatch 一个 “action” 来指明 “用户刚刚做了什么”。(而状态更新逻辑则保存在其他地方!)因此,我们不再通过事件处理器直接 “设置 task”,而是 dispatch 一个 “添加/修改/删除任务” 的 action。这更加符合用户的思维。

action 对象可以有多种结构。按照惯例,我们通常会添加一个字符串类型的 type 字段来描述发生了什么,并通过其它字段传递额外的信息。type 是特定于组件的,选一个能描述清楚发生的事件的名字!

2. 计数器案例

在这个案例中,要实现一个可以增加和减少数字的计数器,效果如下:

点击+号按钮自增,点击-号按钮自减。

function Counter() {
  const initState = { count: 0 };
  function reducer(state, action) {
    switch (action.type) {
      case 'increment':
        return { count: state.count + 1 };
      case 'decrement':
        return { count: state.count - 1 };
      default:
        return { count: state };
    }
  }
  const [state, dispatch] = useReducer(reducer, initState);
  return (
    <div>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <span>{state.count}</span>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
    </div>
  );
}

在这个案例中,我们定义了一个 reducer 函数处理不同操作需要更新的状态。在点击按钮时,调用 useReducer 返回的 dispatch 方法,传递操作类型给 reducer 函数,然后按对应方法更新状态。

reducer 函数就是我们放置状态逻辑的地方。它接受两个参数,分别为当前 state 和 action 对象,并且返回的是更新后的 state,react 会将状态设置为从 reducer 返回的状态。

在 reducers 中使用 switch 语句是一种惯例,和使用 if/else 的结果是相同的,但 switch 语句读起来一目了然。

六、useMemo

1. useMemo 简介

useMemo 是一种性能优化的手段,主要用途就是对状态 state 的记忆,并且还具有缓存功能,类似于 vue 中的计算属性。还有一个作用,避免在代码中参与大量运算。

useMemo 接收2个参数,第1个参数为执行运算的函数,第2个参数为要监控的状态。

2. 使用 useMemo

还是计数器案例,使用 useMemo 通过计数器当前值计算出一个新的值展示在页面上。

function Counter() {
  const [count, setCount] = useState(0);
  const value = useMemo(function () {
    return count * 10;
  }, [count]); // 数组中的元素就是 useMemo 监控的状态
  return (
    <div>
      <h3>{count}</h3>
      <h3>{value}</h3>
      <button onClick={() => setCount(count + 1)}>按钮</button>
    </div>
  );
}

 在这个案例中,我们使用 useState 定义了一个计数器。使用 useMemo 定义了一个 value 状态,代表 useMemo 中计算结果的值。

useMemo 会监控第2个参数数组中的状态,当对应状态更新时,才会执行 useMemo。

七、useRef

1. useRef 简介

useRef 用于获取组件中的 dom 对象。

2. useRef 使用

在组件的属性中加入 ref 属性为存储 useRef 的返回值的变量,就可以获取到这个组件的 dom 对象。

function App() {
  const refObj = useRef();
  console.log(refOjb);
  function getRef() {
    console.log(refObj);
  }
  return (
    <div>
      <div ref={refObj}>hello</div>
      <button onClick={getRef}>按钮</button>
    </div>
  );
}

current 属性为获取到的 dom 对象。

第一次打印出的 refObj 的 current 属性为 undefined,因为这时页面元素还未挂载。当点击按钮时,就会获取到 div 的 dom 对象了。

八、memo

1. memo 简介

memo 是一个高阶组件(参数又是一个组件),功能是对组件进行记忆。

2. memo 使用

先来看一个案例:

function App() {
  const [count, setCount] = useState(0);
  const fn = function () {
    console.log('hahaha');
  };
  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>增加</button>
      <Heads fn={fn}></Heads>
    </div>
  );
}

function Heads(props) {
  console.log('我被渲染了');
  return <button>按钮</button>;
}

在这个案例中,我们定义了一个父组件 App 和一个子组件 Heads。接下来查看在 count 变化时,子组件是否重新被渲染,答案是肯定的,子组件被渲染了多次。

但这个过程中子组件没有改变,重新渲染多次显然不好。

当前组件内的视图没有发生改变,但被重渲染了,这时就需要借助 memo。

function App() {
  const [count, setCount] = useState(0);
  const fn = function () {
    console.log('hahaha');
  };
  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>增加</button>
      <Heads fn={fn}></Heads>
    </div>
  );
}

const Heads = memo(function (props) {
  console.log('我被渲染了');
  return <button>按钮</button>;
});

memo 的参数是一个组件,返回值为一个高阶组件,可以对传入的组件进行记忆,不修改就不会重新渲染。

但上述案例中,点击按钮时子组件还是会重新渲染。原因在于父组件给子组件传递了一个 fn,当点击按钮时,父组件重新渲染导致 fn 被赋值,fn 修改就会导致子组件重新渲染。

修改代码如下:

function App() {
  const [count, setCount] = useState(0);
  const fn = function () {
    console.log('hahaha');
  };
  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>增加</button>
      <Heads></Heads>
    </div>
  );
}

const Heads = memo(function (props) {
  console.log('我被渲染了');
  return <button>按钮</button>;
});

删除给子组件传入的 fn,这时再点击按钮,子组件就不会重新渲染了。

要实现前面的案例传入 fn 不让子组件重新渲染,需要使用 useCallback Hook。

九、useCallback

1. useCallback 简介

useCallback 是一个允许我们在多次渲染中缓存函数的 React Hook,它返回一个 memoized 回调函数。

useMemo 是对数据的记忆,useCallback 是对函数的记忆。

useCallback 有2个参数,第1个参数为要缓存的函数,第2个参数是一个数组,表示在哪些响应值(包括 props 、state 和所有在组件内部直接声明的变量和函数)变化时更新函数。

2. useCallback 使用

将上面的案例用 useCallback 改写:

function App() {
  const [count, setCount] = useState(1);
  const fn = useCallback(function () {
    return count;
  }, []);
  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>增加</button>
      <Heads fn={fn}></Heads>
    </div>
  );
}

const Heads = memo(function (props) {
  return <button onClick={() => console.log(`我被渲染了${props.fn()}次`)}>按钮</button>;
});

这里我们使用 useCallback 将函数 fn 进行缓存,这时再去点击增加按钮,将不会再重新渲染子组件。

接下来看 useCallback 第2个参数如何使用:

function App() {
  const [count, setCount] = useState(1);
  const fn = useCallback(function () {
    return count;
  }, [count]);
  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>增加</button>
      <Heads fn={fn}></Heads>
    </div>
  );
}

const Heads = memo(function (props) {
  return <button onClick={() => console.log(`我被渲染了${props.fn()}次`)}>按钮</button>;
});

这里我们在 useCallback 中加入了第二个参数,数组中有一个元素 count,表示在 count 变化时更新函数 fn。这时在点击增加按钮,就会重新渲染子组件。

十、自定义 Hook

自定义 Hook 就是自己封装的函数功能和 react 中内置的 Hook 进行结合,用于组件间共享逻辑

自定义 Hook 必须以 use 开头。

下面来封装一个 axios get 请求的自定义 Hook:

const useGet = function ({ path, params }) {
  const [data, setData] = useState({});
  useEffect(() => {
    axios.get(path, params).then(res => {
      setData(res.data);
    });
  }, []);
  return data;
};

我们自定义了一个 Hook useGet,作用是使用 axios 的get 请求方式请求接口数据。

function App() {
  const data = useGet({ path: 'https://conduit.productionready.io/api/articles', params: {}});
  if (!data.articles) {
    return <div>
      请求中...
    </div>;
  }
  return (
    <div>
      {data.articles.map(item => <p>{item.title}</p>)}
    </div>
  );
}

使用时和使用内置 Hook 一样的形式使用自定义 Hook。这里我们通过 useGet 获取到接口中的文章数据,并将它们的标题展示在页面上。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学生适合用什么台灯护眼?暑假适合孩子学习的台灯分享

又要临近暑假了&#xff0c;孩子们又要开始整天围着手机、电视、平板等等&#xff0c;想想就感觉到头疼。也有些家长趁着暑假期间给孩子报一下兴趣班&#xff0c;培养一下孩子的技能和情操。不过也要注意孩子的视力健康&#xff0c;不少孩子就是因为在暑假期间没有注意用眼习惯…

Camtasia 2023.1.0免费版电脑视频录制和剪辑软件

Camtasia Studio是一套专业的屏幕录像软件&#xff0c;同时包含Camtasia 录像器、Camtasia Studio&#xff08;编辑器&#xff09;、Camtasia 菜单制作器、Camtasia 剧场、Camtasia 播放器和Screencast的内置功能。Camtasia 是一款专门捕捉屏幕影音的工具软件。它能在任何模式下…

企业金蝶云星空服务器数据库中了locked勒索病毒如何应对

近日&#xff0c;很多企业的金蝶云星空财务账套被locked勒索病毒攻击&#xff0c;财务系统内的许多重要数据被加密&#xff0c;无法正常打开&#xff0c;计算机内的所有文件的扩展名全部都变成了.locked后缀勒索病毒&#xff0c;导致服务器数据库被锁定。这种情况的出现与企业的…

云原生之深入解析K8S Istio Gateway服务的架构分析与实战操作

一、概述 Istio 提供一种简单的方式来为已部署的服务建立网络&#xff0c;该网络具有负载均衡、服务间认证、监控、网关等功能&#xff0c;而不需要对服务的代码做任何改动。 istio 适用于容器或虚拟机环境&#xff08;特别是 k8s&#xff09;&#xff0c;兼容异构架构&#x…

6.1 计算机网络应用模式

6.1 计算机网络应用模式 计算机网络应用模式与计算机网络的发展密切相关&#xff0c;大体可以分为三个阶段 以大型机为中心的应用模式&#xff08;mainframe-centric&#xff09; 该应用模式也称为分时共享&#xff08;time-sharing&#xff09;模式&#xff0c;也就是面向终端…

配置IOC的方式(配置文件和注解)

目录 背景实现xml方式实现结果&#xff1a; 注解方式实现效果&#xff1a; 升华 背景 我们已经学些了IOC概念和原理详情请见 一篇文章解释清楚IOC和DI 下面说如何实现IOC容器的效果。 实现 首先引入jar包 <dependency><groupId>org.springframework</groupId…

Prometheus - Concept

一 Prometheus 是什么 Prometheus 是一个开源的 监控和报警系统 。该系统内置和基于时间序列地抓取、存储、查询、绘图数据、报警。 现在是一个开源项目&#xff0c;继 K8S 后的第二个云原生计算基金会的托管项目&#xff0c;可见其火爆程度。 二 Prometheus 的特征 Promet…

异构系统的对接互通,天翎低代码平台有高招

编者按&#xff1a;企业内部里&#xff0c;最难的就是跨系统、跨应用的对接问题&#xff0c;系统之间的阻隔是影响业务效率的重要原因之一&#xff0c;如今随着技术的发展&#xff0c;这个问题上天翎低代码平台在异构系统对接方面提供多元化、多层次的方式让企业高效低成本的打…

python处理yaml、ini和execl文件

一、yaml的初步了解 YAML 是一个被广泛使用的数据序列化和配置语言&#xff0c;后缀可以为yaml或yml, 支持#注释&#xff0c;通过缩进表示层级&#xff0c;区分大小写&#xff0c;读取出来之后是一个字典列表 yaml 的用途&#xff1a; 用于做配置文件 &#xff08;yaml &…

【每天40分钟,我们一起用50天刷完 (剑指Offer)】第十八天 18/50【层序遍历二叉树(两个队列一个遍历上一层,一个记录下一层)】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

数字虚拟人物制作为多个行业中的智能应用场景赋能

虚拟人物制作的广义定义为数字化外形的虚拟人物&#xff0c;是“虚拟”(存在于非物理世界中)“数字”(由计算机图形学、图形染、动作捕捉、深度学习、语音合成等计算机手段创造及使用)“人”(具有多重人类特征&#xff0c;如外貌、人类表演/交互能力等)的综合产物。 制作一个虚…

Hbase drop 表卡住没有响应

在实际工作中遇到过重新创建一个hbase的hive外部表&#xff0c;在 disable table_name; drop table_name 在drop table_name卡住 最后有提示报错。 建议各位查看下表有无lock的情况&#xff0c; 查看和释放hbase lock可以通过如下方式来查看 pid获取&#xff1a; 在 Ma…

idea支持vue文件-设置对vue的支持

一、idea支持.vue文件 这一步其实就是安装vue.js插件&#xff0c;具体路径为&#xff1a;File ----> Settings ----> Plugins ----> 输入vue&#xff0c;点击搜索结果里的vue.js右边的install按钮&#xff0c;安装成功后重启idea&#xff0c;这样idea就能识别.vue文件…

惨痛面经,做个记录

今天的行情太难了&#xff0c;找工作的还是比较艰难的一个过程。不和哪些优秀的人对比&#xff0c;我就是普通二本院校&#xff0c;工作4年&#xff0c;能力一般般&#xff0c;努力奋斗的一个搬砖人。分享一个月比较惨痛的找工作经历。 简历这一块自己准备的时间比较长&#xf…

争夺数据黑匣子市场,谁将接盘这家Tier1的被动安全业务

在相继卖掉智驾软件算法资产&#xff08;高通收购&#xff09;、主动安全传感器及系统业务&#xff08;麦格纳收购&#xff09;后&#xff0c;Veoneer最后剩余的被动安全系统业务&#xff08;主要是安全气囊ECU&#xff09;也在寻找产业买家。 本周&#xff0c;美国私募股权公司…

Docker Swarm安装PXC高可用集群

docker安装PXC集群 创建数据卷创建集群专用网络创建证书 主流mysql高可用的方式有以下几种 准备三台服务器 hostIP说明node1192.168.31.130PXC集群1node2192.168.31.131PXC集群2node3192.168.31.132PXC集群3 创建docker swarm集群 主节点node1执行 #docker swarm init --ad…

Camera API2 使用说明

CameraAPI1 使用说明 目录 一、 概览 1.1 Pipeline 1.2 Supported Hardware Level 1.3 Capture 1.4 CameraManager 1.5 CameraCharacteristics 1.6 CameraDevice 1.7 Surface 1.8 CameraCaptureSession 1.9 CaptureRequest 1.10 CaptureResult 1.11 一些只有 Came…

基于 Arduino 库实现 ESP32 TCP Server 应用例程

实现步骤&#xff1a; ESP32 开启 WiFi Station 模式连接路由器连上路由器后将获取到分配的 IP 地址基于分配的 IP 地址创建 TCP Server 测试代码如下&#xff1a; #include <WiFi.h> #include <WiFiClient.h>const char* ssid "cc2.4"; const char*…

《水经注地图服务》发布的影像数据在ArcMap中调用

当有用户需要发布一个省以上的海量卫星影像数据时&#xff0c;我们就会强烈建议他使用《水经注地图服务》&#xff08;WeServer&#xff09;进行发布。 因为&#xff0c;《水经注地图服务》在经过我们工程师的不断升级优化之后&#xff0c;现在发布全球100TB级卫星影像数据所需…

【用户调研】需求挖掘

文章目录 用户需求的定义为什么要挖掘用户需求需求挖掘方法用户访谈问卷调查可用性测试运营数据分析 用户访谈介绍实地研究用户观察用户访谈焦点小组 调查问卷介绍总结 用户需求的定义 为什么要挖掘用户需求 需求挖掘方法 用户访谈 问卷调查 可用性测试 运营数据分析 用户访谈介…