React系列教程(2)React哲学

豆约翰习惯将掌握某一技术分为5个层次:初窥门径,小试牛刀,渐入佳境,得心应手,玩转自如

本篇属于React框架中的第1层次即初窥门径

我们认为,React 是用 JavaScript 构建快速响应的大型 Web 应用程序的首选方式。它在 Facebook 和 Instagram 上表现优秀。

React 最棒的部分之一是引导我们思考如何构建一个应用。在这篇文档中,我们将会通过 React 构建一个可搜索的产品数据表格来更深刻地领会 React 哲学。

从设计稿开始

假设我们已经有了一个返回 JSON 的 API,以及设计师提供的组件设计稿。如下所示:

Mockup

该 JSON API 会返回以下数据:

[
  {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
  {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
  {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
  {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
  {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
  {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
];

第一步:将设计好的 UI 划分为组件层级

首先,你需要在设计稿上用方框圈出每一个组件(包括它们的子组件),并且以合适的名称命名。如果你是和设计师一起完成此任务,那么他们可能已经做过类似的工作,所以请和他们进行交流!他们的 Photoshop 的图层名称可能最终就是你编写的 React 组件的名称!

但你如何确定应该将哪些部分划分到一个组件中呢?你可以将组件当作一种函数或者是对象来考虑,根据[单一功能原则]来判定组件的范围。也就是说,一个组件原则上只能负责一个功能。如果它需要负责更多的功能,这时候就应该考虑将它拆分成更小的组件。

在实践中,因为你经常是在向用户展示 JSON 数据模型,所以如果你的模型设计得恰当,UI(或者说组件结构)便会与数据模型一一对应,这是因为 UI 和数据模型都会倾向于遵守相同的信息结构。将 UI 分离为组件,其中每个组件需与数据模型的某部分匹配。

Component diagram

你会看到我们的应用中包含五个组件。我们已经将每个组件展示的数据标注为了斜体。

  1. FilterableProductTable (橙色): 是整个示例应用的整体
  2. SearchBar (蓝色): 接受所有的用户输入
  3. ProductTable (绿色): 展示数据内容并根据用户输入筛选结果
  4. ProductCategoryRow (天蓝色): 为每一个产品类别展示标题
  5. ProductRow (红色): 每一行展示一个产品

你可能注意到,ProductTable 的表头(包含 “Name” 和 “Price” 的那一部分)并未单独成为一个组件。这仅仅是一种偏好选择,如何处理这一问题也一直存在争论。就这个示例而言,因为表头只起到了渲染数据集合的作用——这与 ProductTable 是一致的,所以我们仍然将其保留为 ProductTable 的一部分。但是,如果表头过于复杂(例如,我们需为其添加排序功能),那么将它作为一个独立的 ProductTableHeader 组件就显得很有必要了。

现在我们已经确定了设计稿中应该包含的组件,接下来我们将把它们描述为更加清晰的层级。设计稿中被其他组件包含的子组件,在层级上应该作为其子节点。

  • FilterableProductTable

    • SearchBar

    • ProductTable

      • ProductCategoryRow
      • ProductRow

第二步:用 React 创建一个静态版本

现在我们已经确定了组件层级,可以编写对应的应用了。最容易的方式,是先用已有的数据模型渲染一个不包含交互功能的 UI。最好将渲染 UI 和添加交互这两个过程分开。这是因为,编写一个应用的静态版本时,往往要编写大量代码,而不需要考虑太多交互细节;添加交互功能时则要考虑大量细节,而不需要编写太多代码。所以,将这两个过程分开进行更为合适。我们会在接下来的代码中体会到其中的区别。

在构建应用的静态版本时,我们需要创建一些会重用其他组件的组件,然后通过 props 传入所需的数据。props 是父组件向子组件传递数据的方式。即使你已经熟悉了 state 的概念,也完全不应该使用 state 构建静态版本。state 代表了随时间会产生变化的数据,应当仅在实现交互时使用。所以构建应用的静态版本时,你不会用到它。

你可以自上而下或者自下而上构建应用:自上而下意味着首先编写层级较高的组件(比如 FilterableProductTable),自下而上意味着从最基本的组件开始编写(比如 ProductRow)。当你的应用比较简单时,使用自上而下的方式更方便;对于较为大型的项目来说,自下而上地构建,并同时为低层组件编写测试是更加简单的方式。

到此为止,你应该已经有了一个可重用的组件库来渲染你的数据模型。由于我们构建的是静态版本,所以这些组件目前只需提供 render() 方法用于渲染。最顶层的组件 FilterableProductTable 通过 props 接受你的数据模型。如果你的数据模型发生了改变,再次调用 ReactDOM.render(),UI 就会相应地被更新。数据模型变化、调用 render() 方法、UI 相应变化,这个过程并不复杂,因此很容易看清楚 UI 是如何被更新的,以及是在哪里被更新的。React 单向数据流(也叫单向绑定)的思想使得组件模块化,易于快速开发。

npx create-react-app think_in_react

index.js改为:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';




class ProductCategoryRow extends React.Component {
  render() {
    const category = this.props.category;
    return (
      <tr>
        <th colSpan="2">
          {category}
        </th>
      </tr>
    );
  }
}

class ProductRow extends React.Component {
  render() {
    const product = this.props.product;
    const name = product.stocked ?
      product.name :
      <span style={{ color: 'red' }}>
        {product.name}
      </span>;

    return (
      <tr>
        <td>{name}</td>
        <td>{product.price}</td>
      </tr>
    );
  }
}

class ProductTable extends React.Component {
  render() {
    const rows = [];
    let lastCategory = null;

    this.props.products.forEach((product) => {
      if (product.category !== lastCategory) {
        rows.push(
          <ProductCategoryRow
            category={product.category}
            key={product.category} />
        );
      }
      rows.push(
        <ProductRow
          product={product}
          key={product.name} />
      );
      lastCategory = product.category;
    });

    return (
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Price</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>
    );
  }
}

class SearchBar extends React.Component {
  render() {
    return (
      <form>
        <input type="text" placeholder="Search..." />
        <p>
          <input type="checkbox" />
          {' '}
      Only show products in stock
    </p>
      </form>
    );
  }
}

class FilterableProductTable extends React.Component {
  render() {
    return (
      <div>
        <SearchBar />
        <ProductTable products={this.props.products} />
      </div>
    );
  }
}


const PRODUCTS = [
  { category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football' },
  { category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball' },
  { category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball' },
  { category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch' },
  { category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5' },
  { category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7' }
];

ReactDOM.render(
  <FilterableProductTable products={PRODUCTS} />,
  document.getElementById('root')
);


第三步:确定 UI state 的最小(且完整)表示

想要使你的 UI 具备交互功能,需要有触发基础数据模型改变的能力。React 通过实现 state 来完成这个任务。

为了正确地构建应用,你首先需要找出应用所需的 state 的最小表示,并根据需要计算出其他所有数据。其中的关键正是 [DRY: Don’t Repeat Yourself]。只保留应用所需的可变 state 的最小集合,其他数据均由它们计算产生。比如,你要编写一个任务清单应用,你只需要保存一个包含所有事项的数组,而无需额外保存一个单独的 state 变量(用于存储任务个数)。当你需要展示任务个数时,只需要利用该数组的 length 属性即可。

我们的示例应用拥有如下数据:

  • 包含所有产品的原始列表
  • 用户输入的搜索词
  • 复选框是否选中的值
  • 经过搜索筛选的产品列表

通过问自己以下三个问题,你可以逐个检查相应数据是否属于 state:

  1. 该数据是否是由父组件通过 props 传递而来的?如果是,那它应该不是 state。
  2. 该数据是否随时间的推移而保持不变?如果是,那它应该也不是 state。
  3. 你能否根据其他 state 或 props 计算出该数据的值?如果是,那它也不是 state。

包含所有产品的原始列表是经由 props 传入的,所以它不是 state;搜索词和复选框的值应该是 state,因为它们随时间会发生改变且无法由其他数据计算而来;经过搜索筛选的产品列表不是 state,因为它的结果可以由产品的原始列表根据搜索词和复选框的选择计算出来。

综上所述,属于 state 的有:

  • 用户输入的搜索词
  • 复选框是否选中的值

第四步:确定 state 放置的位置

我们已经确定了应用所需的 state 的最小集合。接下来,我们需要确定哪个组件能够改变这些 state,或者说拥有这些 state。

注意:React 中的数据流是单向的,并顺着组件层级从上往下传递。哪个组件应该拥有某个 state 这件事,对初学者来说往往是最难理解的部分。尽管这可能在一开始不是那么清晰,但你可以尝试通过以下步骤来判断:

对于应用中的每一个 state:

  • 找到根据这个 state 进行渲染的所有组件。
  • 找到他们的共同所有者(common owner)组件(在组件层级上高于所有需要该 state 的组件)。
  • 该共同所有者组件或者比它层级更高的组件应该拥有该 state。
  • 如果你找不到一个合适的位置来存放该 state,就可以直接创建一个新的组件来存放该 state,并将这一新组件置于高于共同所有者组件层级的位置。

根据以上策略重新考虑我们的示例应用:

  • ProductTable 需要根据 state 筛选产品列表。SearchBar 需要展示搜索词和复选框的状态。
  • 他们的共同所有者是 FilterableProductTable
  • 因此,搜索词和复选框的值应该很自然地存放在 FilterableProductTable 组件中。

很好,我们已经决定把这些 state 存放在 FilterableProductTable 组件中。首先,将实例属性 this.state = {filterText: '', inStockOnly: false} 添加到 FilterableProductTableconstructor 中,设置应用的初始 state;接着,将 filterTextinStockOnly 作为 props 传入 ProductTableSearchBar;最后,用这些 props 筛选 ProductTable 中的产品信息,并设置 SearchBar 的表单值。

你现在可以看到应用的变化了:将 filterText 设置为 "ball" 并刷新应用,你能发现表格中的数据已经更新了。

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
// import App from './App';
import * as serviceWorker from './serviceWorker';



class ProductCategoryRow extends React.Component {
  render() {
    const category = this.props.category;
    return (
      <tr>
        <th colSpan="2">
          {category}
        </th>
      </tr>
    );
  }
}

class ProductRow extends React.Component {
  render() {
    const product = this.props.product;
    const name = product.stocked ?
      product.name :
      <span style={{ color: 'red' }}>
        {product.name}
      </span>;

    return (
      <tr>
        <td>{name}</td>
        <td>{product.price}</td>
      </tr>
    );
  }
}

class ProductTable extends React.Component {
  render() {
    const filterText = this.props.filterText;
    const inStockOnly = this.props.inStockOnly;

    const rows = [];
    let lastCategory = null;

    this.props.products.forEach((product) => {
      if (product.name.indexOf(filterText) === -1) {
        return;
      }
      if (inStockOnly && !product.stocked) {
        return;
      }
      if (product.category !== lastCategory) {
        rows.push(
          <ProductCategoryRow
            category={product.category}
            key={product.category} />
        );
      }
      rows.push(
        <ProductRow
          product={product}
          key={product.name}
        />
      );
      lastCategory = product.category;
    });

    return (
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Price</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>
    );
  }
}

class SearchBar extends React.Component {
  render() {
    const filterText = this.props.filterText;
    const inStockOnly = this.props.inStockOnly;

    return (
      <form>
        <input
          type="text"
          placeholder="Search..."
          value={filterText} />
        <p>
          <input
            type="checkbox"
            checked={inStockOnly} />
          {' '}
      Only show products in stock
    </p>
      </form>
    );
  }
}

class FilterableProductTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      filterText: '',
      inStockOnly: false
    };
  }

  render() {
    return (
      <div>
        <SearchBar
          filterText={this.state.filterText}
          inStockOnly={this.state.inStockOnly}
        />
        <ProductTable
          products={this.props.products}
          filterText={this.state.filterText}
          inStockOnly={this.state.inStockOnly}
        />
      </div>
    );
  }
}


const PRODUCTS = [
  { category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football' },
  { category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball' },
  { category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball' },
  { category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch' },
  { category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5' },
  { category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7' }
];

ReactDOM.render(
  <FilterableProductTable products={PRODUCTS} />,
  document.getElementById('root')
);


第五步:添加反向数据流

到目前为止,我们已经借助自上而下传递的 props 和 state 渲染了一个应用。现在,我们将尝试让数据反向传递:处于较低层级的表单组件更新较高层级的 FilterableProductTable 中的 state。

React 通过一种比传统的双向绑定略微繁琐的方法来实现反向数据传递。尽管如此,但这种需要显式声明的方法更有助于人们理解程序的运作方式。

如果你在这时尝试在搜索框输入或勾选复选框,React 不会产生任何响应。这是正常的,因为我们之前已经将 input 的值设置为了从 FilterableProductTablestate 传递而来的固定值。

让我们重新梳理一下需要实现的功能:每当用户改变表单的值,我们需要改变 state 来反映用户的当前输入。由于 state 只能由拥有它们的组件进行更改,FilterableProductTable 必须将一个能够触发 state 改变的回调函数(callback)传递给 SearchBar。我们可以使用输入框的 onChange 事件来监视用户输入的变化,并通知 FilterableProductTable 传递给 SearchBar 的回调函数。然后该回调函数将调用 setState(),从而更新应用。

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
// import App from './App';
import * as serviceWorker from './serviceWorker';





class ProductCategoryRow extends React.Component {
  render() {
    const category = this.props.category;
    return (
      <tr>
        <th colSpan="2">
          {category}
        </th>
      </tr>
    );
  }
}

class ProductRow extends React.Component {
  render() {
    const product = this.props.product;
    const name = product.stocked ?
      product.name :
      <span style={{ color: 'red' }}>
        {product.name}
      </span>;

    return (
      <tr>
        <td>{name}</td>
        <td>{product.price}</td>
      </tr>
    );
  }
}

class ProductTable extends React.Component {
  render() {
    const filterText = this.props.filterText;
    const inStockOnly = this.props.inStockOnly;

    const rows = [];
    let lastCategory = null;

    this.props.products.forEach((product) => {
      if (product.name.indexOf(filterText) === -1) {
        return;
      }
      if (inStockOnly && !product.stocked) {
        return;
      }
      if (product.category !== lastCategory) {
        rows.push(
          <ProductCategoryRow
            category={product.category}
            key={product.category} />
        );
      }
      rows.push(
        <ProductRow
          product={product}
          key={product.name}
        />
      );
      lastCategory = product.category;
    });

    return (
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Price</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>
    );
  }
}

class SearchBar extends React.Component {
  constructor(props) {
    super(props);
    this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
    this.handleInStockChange = this.handleInStockChange.bind(this);
  }

  handleFilterTextChange(e) {
    this.props.onFilterTextChange(e.target.value);
  }

  handleInStockChange(e) {
    this.props.onInStockChange(e.target.checked);
  }

  render() {
    return (
      <form>
        <input
          type="text"
          placeholder="Search..."
          value={this.props.filterText}
          onChange={this.handleFilterTextChange}
        />
        <p>
          <input
            type="checkbox"
            checked={this.props.inStockOnly}
            onChange={this.handleInStockChange}
          />
          {' '}
      Only show products in stock
    </p>
      </form>
    );
  }
}

class FilterableProductTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      filterText: '',
      inStockOnly: false
    };

    this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
    this.handleInStockChange = this.handleInStockChange.bind(this);
  }

  handleFilterTextChange(filterText) {
    this.setState({
      filterText: filterText
    });
  }

  handleInStockChange(inStockOnly) {
    this.setState({
      inStockOnly: inStockOnly
    })
  }

  render() {
    return (
      <div>
        <SearchBar
          filterText={this.state.filterText}
          inStockOnly={this.state.inStockOnly}
          onFilterTextChange={this.handleFilterTextChange}
          onInStockChange={this.handleInStockChange}
        />
        <ProductTable
          products={this.props.products}
          filterText={this.state.filterText}
          inStockOnly={this.state.inStockOnly}
        />
      </div>
    );
  }
}


const PRODUCTS = [
  { category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football' },
  { category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball' },
  { category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball' },
  { category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch' },
  { category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5' },
  { category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7' }
];

ReactDOM.render(
  <FilterableProductTable products={PRODUCTS} />,
  document.getElementById('root')
);


这就是全部了

希望这篇文档能够帮助你建立起构建 React 组件和应用的一般概念。尽管你可能需要编写更多的代码,但是别忘了:比起写,代码更多地是给人看的。我们一起构建的这个模块化示例应用的代码就很易于阅读。当你开始构建更大的组件库时,你会意识到这种代码模块化和清晰度的重要性。并且随着代码重用程度的加深,你的代码行数也会显著地减少。:)

最后编辑于:2024-10-27 15:39:36


喜欢的朋友记得点赞、收藏、关注哦!!!

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

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

相关文章

无人机声学侦测算法详解!

一、算法原理 无人机在飞行过程中&#xff0c;其电机工作、旋翼震动以及气流扰动等都会产生一定程度的噪声。这些噪声具有独特的声学特征&#xff0c;如频率范围、时域和频域特性等&#xff0c;可以用于无人机的检测与识别。声学侦测算法利用这些特征&#xff0c;通过一系列步…

【C++】继承的理解

1.继承的概念和定义 1.1继承的概念 继承 (inheritance) 机制是面向对象程序设计 使代码可以复用 的最重要的手段&#xff0c;它允许程序员在 保 持原有类特性的基础上进行扩展 &#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承 呈现了面向对象 程序…

车圈大厂9月利润率惨淡收尾,“金九”或变“铜九”

撰文&#xff5c;ANGELICA 编辑&#xff5c;ANGELICA 审核&#xff5c;烨 Lydia 声明&#xff5c;图片来源网络。日晞研究所原创文章&#xff0c;如需转载请留言申请开白。 国庆假期第一天&#xff0c;不少车企就迫不及待晒出假期战报。 按照以往的经验&#xff0c;每年9月…

蓝牙是如何诞生,如何工作,如何发展的?【无线通信小百科】

蓝牙为什么叫蓝牙&#xff1f;深入了解关于蓝牙的一切|无线通信小百科 在前两期文章&#xff0c;我们为大家介绍了无限通信技术是如何工作&#xff0c;如何发展&#xff1b;也为大家讲解了目前主流无线通信模块、SoC方案都有哪些。 无线通信工作原理、发展历程介绍https://blo…

Pytorch cuda版本选择(简洁高效版)

简而言之 Pytorch cuda版本选择 只需要低于cuda驱动版本即可&#xff0c;cuda版本查看是nvidia-smi, nvcc -V 是runtimeapi版本可以不用管 1.只要看cuda驱动版本 安装pytorch 选择cuda版本&#xff0c;只要看你电脑cuda驱动版本即可。 2.选择依据 pytorch中cuda版本只要不高于…

告别复杂协作:Adobe XD的简化替代方案

Adobe XD是一款集成UI/UX设计和原型创建功能的设计平台。它允许用户进行网页、移动应用的设计&#xff0c;以及原型的绘制&#xff0c;并且能够将静态设计转化为动态的交互原型。尽管Adobe XD提供了这些功能&#xff0c;但它依赖于第三方插件&#xff0c;且插件库有限&#xff…

【创新技术】探索Nuvoton NSP2.0:打造高品质语音提示新方案

你还在为寻找低成本高品质的语音播放芯片而困扰吗&#xff1f;面对市面上参差不齐的语音播放芯片&#xff0c;我们一直都在追求性价比&#xff0c;真正的性价比并不单独只是考虑价格&#xff0c;更加考虑播放音效的品质&#xff0c;芯片的抗干扰性能、外围电路的简易程度和开发…

【IC每日一题:CDC多bits跨时钟传输+handShake】

IC每日一题&#xff1a;CDC多bits跨时钟传输handShake 1 八股题&#xff1a;CDC多bits跨时钟传输1.1 慢到快&#xff1a;MUX enbale同步器法1.1.1 分析1.1.2 时序图1.1.3 代码 1.2 快到慢&#xff1a;握手协议1.2.1 原理分析1.2.2 时序图1.2.3 代码题 2 手撕题&#xff1a;使用…

如何将MySQL彻底卸载干净

目录 背景&#xff1a; MySQL的卸载 步骤1&#xff1a;停止MySQL服务 步骤2&#xff1a;软件的卸载 步骤3&#xff1a;残余文件的清理 步骤4&#xff1a;清理注册表 步骤五:删除环境变量配置 总结&#xff1a; 背景&#xff1a; MySQL卸载不彻底往往会导致重新安装失败…

完美解决 vscode 多设备通过ssh登录远程服务器免密登录

文章目录 问题解决分支一&#xff1a;只需一个设备连服务器分支二&#xff1a;需要多台设备连服务器&#xff08;即分支一成立的情况下&#xff0c;即已经有一个设备连接服务器了&#xff09;确保权限正确注意 问题 麻烦&#xff0c;每次打开vscode都要输入密码才能连接服务器&…

mac|安装redis及RedisDesk可视化软件

一、安装 通过Homebrew安装 brew install redis 在安装过程可以得到以下信息&#xff1a; 1、启动redis或重新登陆redis brew services start redis 如果只想在前端运行&#xff0c;而不是在后端&#xff0c;则使用以下命令 /opt/homebrew/opt/redis/bin/redis-server /opt…

大学适合学C语言还是Python?

在大学学习编程时&#xff0c;选择C语言还是Python&#xff0c;这主要取决于你的学习目标、专业需求以及个人兴趣。以下是对两种语言的详细比较&#xff0c;帮助你做出更明智的选择&#xff1a; C语言 优点&#xff1a; 底层编程&#xff1a;C语言是一种底层编程语言&#x…

3大关键点教你用Java和Spring Boot快速构建微服务架构:从零开发到高效服务注册与发现的逆袭之路

你好&#xff0c;我是忆~遂愿&#xff0c;全网3w粉丝&#xff0c;《遂愿盈创》社群主理人。 副业启航① | 遂愿盈创&#xff08;对副业感兴趣免费可入&#xff0c;多种赚钱实战项目等你来&#xff0c;一起探寻副业快速变现的途径&#xff1b;以及对接互联网大厂商务合作&#x…

ubuntu下使用pocketsphinx进行语音识别

文章目录 前言一、pocketsphinx的介绍二、ubuntu下编译三、使用示例1.模型选择2.代码示例3.自定义字典 四、交叉编译总结 前言 由于工作需要语音识别的功能&#xff0c;环境是在linux arm版上&#xff0c;所以想先在ubuntu上跑起来看一看&#xff0c;就找了一下语音识别的开源…

Redis的持久化以及性能管理

目录 一、Redis持久化概述 1.什么是Redis持久化 2.持久化方式 3.RDB持久化 3.1概念 3.2触发条件 3.3执行流程 3.4启动时加载 4. AOF持久化 4.1概念 4.2启动AOF 4.3执行流程 4.4启动时加载 5.RDB和AOF的优缺点 二、Redis性能管理 1.查看Redis内存使用 2…

科研绘图系列:R语言组合连线图和箱线图(linechart+boxplot)

文章目录 介绍加载R包数据数据预处理画图1画图2系统信息介绍 连线图(Line Chart)是一种常用的数据可视化图表,它通过将一系列数据点用直线段连接起来来展示数据随时间或有序类别变化的趋势。以下是连线图可以表示的一些内容: 时间序列数据:展示数据随时间变化的趋势,例如…

Webserver(3.1)线程

目录 创建线程终止线程连接已终止的进程二级指针 线程分离线程取消线程属性线程同步多线程卖票 创建线程 编译时需要加-pthread gcc pthread_create.c -o create -pthread#include<pthread.h> #include<stdio.h> #include<string.h> #include<unistd.h&…

WPS实现手机电脑同步文件

复制链接&#xff0c;发送微信&#xff0c;即可在手机端打开同步编辑文档。 当手机编辑文档后&#xff0c;会有如下提示: 根据提示&#xff0c;可选择文件更新版本。

ES海量数据插入如何优化性能?

2024年10月NJSD技术盛典暨第十届NJSD软件开发者大会、第八届IAS互联网架构大会在南京召开。百度文心快码总经理臧志分享了《AI原生研发新范式的实践与思考》&#xff0c;探讨了大模型赋能下的研发变革及如何在公司和行业中落地&#xff0c;AI原生研发新范式的内涵和推动经验。 …

【linux】HTTPS 协议原理

1. 了解 HTTPS 协议原理 &#xff08;一&#xff09;认识 HTTPS HTTPS 也是一种应用层协议&#xff0c;是在 HTTP 协议的基础上引入了一个加密层 因为 HTTP协议的内容都是按照文本的方式进行传输的&#xff0c;这个过程中&#xff0c;可能会出现一些篡改的情况 &#xff08;…