【React】React学习:从初级到高级(三)

news2025/1/21 15:45:34

3 状态管理

随着应用不断变大,应该更有意识的去关注应用状态如何组织,以及数据如何在组件之间流动。冗余或重复的状态往往是缺陷的根源。

3.1 用State响应输入

3.1.1 声明式地考虑UI

总体步骤如下:

  1. 定位组件中不同的视图状态

  2. 确定是什么触发了这些 state 的改变

    • 人为输入,人为输入一般需要事件处理函数
    • 计算机输入
  3. 表示内存中的 state(需要使用 useState

    • 需要让“变化的部分”尽可能的少,可以先从必须的状态开始
    • 刚开始若不确定可以设置多一些视图状态,之后不断尝试重构state
  4. 删除任何不必要的 state 变量

    • 这个 state 是否会导致矛盾

    • 相同的信息是否已经在另一个 state 变量中存在

    • 你是否可以通过另一个 state 变量的相反值得到相同的信息

      Reducer 可以合并多个状态变量到一个对象中并巩固所有相关的逻辑!

  5. 连接事件处理函数去设置 state

    • 创建事件处理函数去设置 state 变量。

同时展示大量的视图状态,这样的页面通常被称作living styleguide或者storybook


挑战:这个表单在两种模式间切换:编辑模式,你可以看到输入框;查看模式,你只能看到结果。按钮的标签会根据你所处的模式在“编辑”和“保存”两者中切换。当你改变输入框的内容时,欢迎信息会最下面实时更新。

import {useState} from 'react';

export default function EditProfile() {
  const [display, setDisplay] = useState(false);
  const [person, setPerson] = useState({
    firstName: 'Joe',
    lastName: 'Stan'
  });

  function handleFirstNameChange(e) {
    setPerson({
      ...person,
      [e.target.name]: e.target.value
    })
  }

  function handleLastNameChange(e) {
    setPerson({
      ...person,
      [e.target.name]: e.target.value
    })
  }
  
  
  return (
    <form onSubmit={e => {
      e.preventDefault(),
      setDisplay(!display)
    }}>
      <label>
        First name:{' '}
        {display ? 
          <input 
            name="firstName"
            value={person.firstName}
            onChange={handleFirstNameChange} /> :
        <b>{person.firstName}</b>
        }
      </label>
      <label>
        Last name:{' '}
        {display ? 
          <input 
            name="lastName" 
            value={person.lastName}
            onChange={handleLastNameChange} /> :
          <b>{person.lastName}</b>
        }

      </label>
      <button type="submit">
      {display ? 'Save' : 'Edit'} Profile
      </button>
      <p><i>Hello, {person.firstName} {person.lastName}!</i></p>
    </form>
  );
}


updateDOM函数展示了当你设置 state 时,React 在幕后都做了什么.

// index.js
let firstName = 'Jane';
let lastName = 'Jacobs';
let isEditing = false;

function handleFormSubmit(e) {
  e.preventDefault();
  setIsEditing(!isEditing);
}

function handleFirstNameChange(e) {
  setFirstName(e.target.value);
}

function handleLastNameChange(e) {
  setLastName(e.target.value);
}

function setFirstName(value) {
  firstName = value;
  updateDOM();
}

function setLastName(value) {
  lastName = value;
  updateDOM();
}

function setIsEditing(value) {
  isEditing = value;
  updateDOM();
}

function updateDOM() {
  if (isEditing) {
    editButton.textContent = 'Save Profile';
    hide(firstNameText);
    hide(lastNameText);
    show(firstNameInput);
    show(lastNameInput);
  } else {
    editButton.textContent = 'Edit Profile';
    hide(firstNameInput);
    hide(lastNameInput);
    show(firstNameText);
    show(lastNameText);
  }
  firstNameText.textContent = firstName;
  lastNameText.textContent = lastName;
  helloText.textContent = (
    'Hello ' +
    firstName + ' ' +
    lastName + '!'
  );
}

function hide(el) {
  el.style.display = 'none';
}

function show(el) {
  el.style.display = '';
}

let form = document.getElementById('form');
let editButton = document.getElementById('editButton');
let firstNameInput = document.getElementById('firstNameInput');
let firstNameText = document.getElementById('firstNameText');
let lastNameInput = document.getElementById('lastNameInput');
let lastNameText = document.getElementById('lastNameText');
let helloText = document.getElementById('helloText');
form.onsubmit = handleFormSubmit;
firstNameInput.oninput = handleFirstNameChange;
lastNameInput.oninput = handleLastNameChange;

/* index.html */
<form id="form">
  <label>
    First name:
    <b id="firstNameText">Jane</b>
    <input
      id="firstNameInput"
      value="Jane"
      style="display: none">
  </label>
  <label>
    Last name:
    <b id="lastNameText">Jacobs</b>
    <input
      id="lastNameInput"
      value="Jacobs"
      style="display: none">
  </label>
  <button type="submit" id="editButton">Edit Profile</button>
  <p><i id="helloText">Hello, Jane Jacobs!</i></p>
</form>

<style>
* { box-sizing: border-box; }
body { font-family: sans-serif; margin: 20px; padding: 0; }
label { display: block; margin-bottom: 20px; }
</style>

3.2 选择state结构

3.1.1 构建state的原则

  • 合并关联的 state

    • 如果某两个 state 变量总是一起变化,则将它们统一成一个 state 变量可能更好
    • 另一种情况是,将数据整合到一个对象或一个数组中时,不知道需要多少个 state 片段
  • 避免互相矛盾的 state

  • 避免冗余的 state

    • “镜像”一些 prop 属性会导致混淆,建议使用常量

      function Message({ messageColor }) {
        const color = messageColor;
      

      只有当想要 忽略特定 props 属性的所有更新时,将 props “镜像”到 state 才有意义。按照惯例,prop 名称以 initialdefault 开头,以阐明该 prop 的新值将被忽略:

      function Message({ initialColor }) {
        // 这个 `color` state 变量用于保存 `initialColor` 的 **初始值**。
        // 对于 `initialColor` 属性的进一步更改将被忽略。
        const [color, setColor] = useState(initialColor);
      
  • 避免重复的 state

  • 避免深度嵌套的 state


3.3 在组件间共享状态(状态提升)

当编写一个组件时,你应该考虑哪些信息应该由父组件控制(通过传递 props),哪些信息应该由内部state控制(通过 state)。

进行状态提升的步骤:

  1. 从子组件中 移除 state 。
  2. 从父组件 传递 props。
  3. 为子组件的共同父组件添加 state ,并将其与事件处理函数一起向下传递

3.4 对state进行保留和重置

React 使用树形结构来对开发者创造的 UI 进行管理和建模。

在这里插入图片描述

3.4.1 state与树中的某个位置相关联

根据组件在 UI 树中的位置,React 将它所持有的每个 state 与正确的组件关联起来。 React 在移除一个组件时,也会销毁它的 state。下面是一个组件的添加与删除。

在这里插入图片描述
在这里插入图片描述

只要一个组件还被渲染在 UI 树的相同位置,React 就会保留它的 state。 如果它被移除,或者一个不同的组件被渲染在相同的位置,那么 React 就会丢掉它的 state。

3.4.2 相同位置的相同组件会保留state

更新 App 的状态不会重置 Counter,因为 Counter 始终保持在同一位置。

import { useState } from 'react';

export default function App() {
  const [isFancy, setIsFancy] = useState(false);
  return (
    <div>
      {isFancy ? (
        <Counter isFancy={true} /> 
      ) : (
        <Counter isFancy={false} /> 
      )}
      <label>
        <input
          type="checkbox"
          checked={isFancy}
          onChange={e => {
            setIsFancy(e.target.checked)
          }}
        />
        使用好看的样式
      </label>
    </div>
  );
}

function Counter({ isFancy }) {
  const [score, setScore] = useState(0);
  const [hover, setHover] = useState(false);

  let className = 'counter';
  if (hover) {
    className += ' hover';
  }
  if (isFancy) {
    className += ' fancy';
  }

  return (
    <div
      className={className}
      onPointerEnter={() => setHover(true)}
      onPointerLeave={() => setHover(false)}
    >
      <h1>{score}</h1>
      <button onClick={() => setScore(score + 1)}>
        加一
      </button>
    </div>
  );
}

在这里插入图片描述

对 React 来说重要的是组件在 UI 树中的位置,而不是在 JSX 中的位置!

3.4.3 相同位置的不同组件会重置state

import { useState } from 'react';

export default function App() {
  const [isPaused, setIsPaused] = useState(false);
  return (
    <div>
      {isPaused ? (
        <p>待会见!</p> 
      ) : (
        <Counter /> 
      )}
      <label>
        <input
          type="checkbox"
          checked={isPaused}
          onChange={e => {
            setIsPaused(e.target.checked)
          }}
        />
        休息一下
      </label>
    </div>
  );
}

function Counter() {
  const [score, setScore] = useState(0);
  const [hover, setHover] = useState(false);

  let className = 'counter';
  if (hover) {
    className += ' hover';
  }

  return (
    <div
      className={className}
      onPointerEnter={() => setHover(true)}
      onPointerLeave={() => setHover(false)}
    >
      <h1>{score}</h1>
      <button onClick={() => setScore(score + 1)}>
        加一
      </button>
    </div>
  );
}

在这里插入图片描述

Counter 变为 p 时,Counter 会被移除,同时 p 被添加。

在这里插入图片描述

当切换回来时,p 会被删除,而 Counter 会被添加。

刚开始 <div> 的第一个子组件是一个 Counter。但是当切换成 p 时,React 将 Counter 从 UI 树中移除了并销毁了它的状态。


当在相同位置渲染不同的组件时,组件的整个子树都会被重置

在这里插入图片描述

section 变为 div 时,section 会被删除,新的 div 被添加

在这里插入图片描述

当切换回来时,div 会被删除,新的 section 被添加。

如果想在重新渲染时保留 state,几次渲染中的树形结构就应该相互“匹配”


3.4.4 在相同位置重置相同组件的state

  • 方法1:将组件渲染在不同位置(适用于只有少数几个组件)

在这里插入图片描述

  • 方法2:使用key赋予每个组件一个明确的身份

    {isPlayerA ? (
      <Counter key="Taylor" person="Taylor" />
    ) : (
      <Counter key="Sarah" person="Sarah" />
    )}
    

    请记住 key 不是全局唯一的。它们只能指定 父组件内部 的顺序。

3.4.5 使用key重置表单

Chat组件添加一个 key,就可以保证每次选择一个不同的收件人时,Chat组件包括其下方树中的state就会被重新创建。

<Chat key={to.id} contact={to} />

3.4.6 为被移除的组件保留state

比如聊天应用

  • 如果UI比较简单,就可以使用CSS把其他聊天隐藏起来
  • 进行状态提升,让父组件保存信息
  • 使用其他数据源

3.5 迁移状态逻辑至Reducer中

3.5.1 使用reducer整合状态逻辑

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

  1. 将设置状态的逻辑 修改dispatch 的一个 action

    比如下面这段代码:

    function handleAddTask(text) {
      setTasks([
        ...tasks,
        {
          id: nextId++,
          text: text,
          done: false,
        },
      ]);
    }
    
    function handleChangeTask(task) {
      setTasks(
        tasks.map((t) => {
          if (t.id === task.id) {
            return task;
          } else {
            return t;
          }
        })
      );
    }
    
    function handleDeleteTask(taskId) {
      setTasks(tasks.filter((t) => t.id !== taskId));
    }
    

    移除所有状态设置逻辑,只留下三个事件处理函数。通过事件处理函数 dispatch 一个 action来指明 “用户刚刚做了什么”。(状态更新逻辑则保存在其他地方!),修改后的代码如下:

    function handleAddTask(text) {
      dispatch(
          // action 对象
          {
            type: 'added',
            id: nextId++,
            text: text,
          }
      );
    }
    
    function handleChangeTask(task) {
      dispatch({
        type: 'changed',
        task: task,
      });
    }
    
    function handleDeleteTask(taskId) {
      dispatch({
        type: 'deleted',
        id: taskId,
      });
    }
    

    action 对象可以有多种结构。

    按照惯例,通常会添加一个字符串类型的 type 字段来描述发生了什么,并通过其它字段传递额外的信息。type 是特定于组件的,在这个例子中 addedaddded_task 都可以。选一个能描述清楚发生的事件的名字!

    dispatch({
      // 针对特定的组件
      type: 'what_happened',
      // 其它字段放这里
    });
    
  2. 编写 一个 reducer 函数;

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

    function yourReducer(state, action) {
      // 给 React 返回更新后的状态
    }
    

    在这个例子中,要将状态设置逻辑从事件处理程序移到 reducer 函数中,你需要:

    1. 声明当前状态(tasks)作为第一个参数;
    2. 声明 action 对象作为第二个参数;
    3. reducer 返回 下一个 状态(React 会将旧的状态设置为这个最新的状态)。
    function tasksReducer(tasks, action) {
      if (action.type === 'added') {
        return [
          ...tasks,
          {
            id: action.id,
            text: action.text,
            done: false,
          },
        ];
      } else if (action.type === 'changed') {
        return tasks.map((t) => {
          if (t.id === action.task.id) {
            return action.task;
          } else {
            return t;
          }
        });
      } else if (action.type === 'deleted') {
        return tasks.filter((t) => t.id !== action.id);
      } else {
        throw Error('未知 action: ' + action.type);
      }
    }
    

    上面语句用了if/else语句,但在reducers中使用switch语句更加一目了然:

    function tasksReducer(tasks, action) {
      switch (action.type) {
        case 'added': {
          return [
            ...tasks,
            {
              id: action.id,
              text: action.text,
              done: false,
            },
          ];
        }
        case 'changed': {
          return tasks.map((t) => {
            if (t.id === action.task.id) {
              return action.task;
            } else {
              return t;
            }
          });
        }
        case 'deleted': {
          return tasks.filter((t) => t.id !== action.id);
        }
        default: {
          throw Error('未知 action: ' + action.type);
        }
      }
    }
    
  3. 在组件中 使用 reducer

事件处理程序只通过派发 action 来指定 发生了什么,而 reducer 函数通过响应 actions 来决定 状态如何更新

3.5.2 对比useState和useReducer

  • 代码体积:UI组件少可以用useState,组件复杂用useReducer
  • 可读性:依据状态更新逻辑复杂程度而定,简单时useState,复杂时useReducer
  • 可调试性:useReducer更佳,可以通过打印日志来调试
  • 可测试性:reducer函数是一个纯函数,可以单独进行测试

3.5.3 编写一个好的reducer函数

  • reducer必须是一个纯函数
  • 每个action都描述了一个单一的用户交互,即便它会引发多个数据的变化

3.5.4 使用Immer简化reducers

引入useImmerReducer:

import { useImmerReducer } from 'use-immer';

使用draft.函数修改state:

function tasksReducer(draft, action) {
  switch (action.type) {
    case 'added': {
      draft.push({
        id: action.id,
        text: action.text,
        done: false,
      });
      break;
    }
    case 'changed': {
      const index = draft.findIndex((t) => t.id === action.task.id);
      draft[index] = action.task;
      break;
    }
    case 'deleted': {
      return draft.filter((t) => t.id !== action.id);
    }
    default: {
      throw Error('未知 action:' + action.type);
    }
  }
}

3.6 使用Context深层传递参数

Context 允许父组件向其下层无论多深的任何组件提供信息,而无需通过 props 显式传递。

  1. 创建context

    // LevelContext.js
    import { createContext } from 'react';
    
    export const LevelContext = createContext(1);
    
    
  2. 使用context

    import { useContext } from 'react';
    import { LevelContext } from './LevelContext.js';
    
    export default function Heading({ children }) {
      const level = useContext(LevelContext);
      // ...
    }
    
  3. 提供context

    用 context provider 包裹起来 以提供 LevelContext 给它们:

    import { LevelContext } from './LevelContext.js';
    
    export default function Section({ level, children }) {
      return (
        <section className="section">
          <LevelContext.Provider value={level}>
            {children}
          </LevelContext.Provider>
        </section>
      );
    }
    

Context 让你可以编写“适应周围环境”的组件,并且根据在哪 (或者说 在哪个 context 中)来渲染它们不同的样子。不同的 React context 不会覆盖彼此。Context 会穿过中间的任何组件。

3.6.1 context的使用场景

  • 主题: 如果你的应用允许用户更改其外观(例如暗夜模式),你可以在应用顶层放一个 context provider,并在需要调整其外观的组件中使用该 context。
  • 当前账户: 许多组件可能需要知道当前登录的用户信息。将它放到 context 中可以方便地在树中的任何位置读取它。
  • 路由: 大多数路由解决方案在其内部使用 context 来保存当前路由。
  • **状态管理:**通常 将 reducer context 搭配使用来管理复杂的状态并将其传递给深层的组件来避免过多的麻烦。

3.7 使用Reducer和Context拓展应用

步骤:

  1. 创建 context。
  2. 将 state 和 dispatch 放入 context。
  3. 在组件树的任何地方 使用 context。

为子组件提供 state 和 dispatch 函数:

  1. 创建两个 context (一个用于 state,一个用于 dispatch 函数)。

    import { createContext } from 'react';
    
    export const TasksContext = createContext(null);
    export const TasksDispatchContext = createContext(null);
    
  2. 让组件的 context 使用 reducer。

    export function TasksProvider({ children }) {
      const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
    
      return (
        <TasksContext.Provider value={tasks}>
          <TasksDispatchContext.Provider value={dispatch}>
            {children}
          </TasksDispatchContext.Provider>
        </TasksContext.Provider>
      );
    }
    // 也可以从 TasksContext.js 中导出使用 context 的函数:
    export function useTasks() {
      return useContext(TasksContext);
    }
    
    export function useTasksDispatch() {
      return useContext(TasksDispatchContext);
    }
    
  3. 使用组件中需要读取的 context。

    // 组件可以通过以下函数读取 context:
    const tasks = useTasks();
    const dispatch = useTasksDispatch();
    

useTasksuseTasksDispatch 这样的函数被称为自定义 Hook, 如果你的函数名以 use 开头,它就被认为是一个自定义 Hook。

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

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

相关文章

C语言---关键词

C语言关键词如下&#xff1a;

centos7快速修改密码

centos7快速修改密码 小白教程&#xff0c;一看就会&#xff0c;一做就成。 1.命令 #第一种&#xff0c;我经常用这个&#xff0c;这个不行了&#xff0c;会用到第二个echo 用户名:密码 | sudo chpasswd #例如下面 echo root:yegoo123 | chpasswd#第二种echo 密码|passwd --st…

Redis之主从复制解读

目录 基本概述 作用 如何配置主从复制 命令配置&#xff08;Slaveof &#xff09; 配置文件配置 主从复制缺点 主从复制原理 主从复制常见问题解答 命令补充&#xff08;info replication&#xff09; 基本概述 主从复制,是指将一台Redis服务器的数据,复制到其他的R…

MySQL分页查询详解:优化大数据集的LIMIT和OFFSET

最近在工作中&#xff0c;我们遇到了一个需求&#xff0c;甲方要求直接从数据库导出一个业务模块中所有使用中的工单信息。为了实现这一目标&#xff0c;我编写了一条SQL查询语句&#xff0c;并请求DBA协助导出数据。尽管工单数量并不多&#xff0c;只有3000多条&#xff0c;但…

国产5G+卫星通信手机推出,加速追赶美国星链,优势是价格更实惠

星链已成为美国在6G时代实现弯道超车的关键&#xff0c;面对着中国在地面移动通信技术上的优势&#xff0c;美国意图依靠卫星通信技术反超&#xff0c;而近期国产5G卫星通信手机的推出&#xff0c;却意味着中国在民用卫星通信技术上领先一步。 一、中国在地面移动通信技术的优势…

【微服务部署】07-调用链追踪

文章目录 集成SkyWalking实现调用链追踪1. SkyWalking架构图2. 代码集成SkyWalking 集成SkyWalking实现调用链追踪 1. SkyWalking架构图 Receiver是SkyWalking的入口&#xff0c;支持gRPC和HTTP协议。 SkyWalking内部有分析和查询两个部分 存储方面SkyWalking支持Elasticsearc…

mybatis源码学习-3-解析器模块

写在前面,这里会有很多借鉴的内容,有以下三个原因 本博客只是作为本人学习记录并用以分享,并不是专业的技术型博客笔者是位刚刚开始尝试阅读源码的人,对源码的阅读流程乃至整体架构并不熟悉,观看他人博客可以帮助我快速入门如果只是笔者自己观看,难免会有很多弄不懂乃至理解错误…

C++实现蜂群涌现效果(flocking)

Flocking算法0704_元宇宙中的程序员的博客-CSDN博客 每个个体的位置&#xff0c;通过计算与周围个体的速度、角度、位置&#xff0c;去更新位置。

【01背包理论】01背包问题dp[i][j](二维数组) <动态规划板子>

【01背包理论】01背包问题 dp[i][j] 有 n 件物品和一个最多能背重量为 w 的背包。 第 i 件物品的重量是 weight[i]&#xff0c;得到的价值是 value[i] 。 每件物品只有一个&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 题解 动态规划 确定 dp 数组以及下标的含义…

使用Docker安装和部署RabbitMQ

&#x1f680; 1 拉取RabbitMQ Docker镜像 首先&#xff0c;使用Docker命令从Docker Hub拉取RabbitMQ官方镜像。打开终端并运行以下命令&#xff1a; docker pull rabbitmq&#x1f680; 2 创建RabbitMQ容器 一旦镜像下载完成&#xff0c;使用以下命令创建RabbitMQ容器&…

报错合集 ing - net::ERR_ABORTED 500 (Internal Server Error)

报错&#xff1a;net::ERR_ABORTED 500 (Internal Server Error) 根据提示找到对应文件 解决&#xff1a;检查代码&#xff0c;根据高亮颜色判断&#xff0c;发现箭头函数漏了一个>。 报错&#xff1a;Uncaught TypeError: Assignment to constant variable. &#xff08…

【负载均衡】常见的负载均衡策略有哪些?

文章目录 前言负载均衡分类常见负载均衡策略小结 前言 负载均衡策略是实现负载均衡器的关键&#xff0c;而负载均衡器又是分布式系统中不可或缺的重要组件。使用它有助于提高系统的整体性能、可用性、可靠性和安全性&#xff0c;同时支持系统的扩展和故障容忍性。对于处理大量…

新建工程——第一个S32DS工程

之前的"测试开发板"章节 测试开发板——第一个AutoSAR程序,使用了一个 demo 工程,不管是裸机程序还是 AutoSAR 程序,那都是别人已经创建好的工程。本节来介绍如何来创建自己的工程,本节介绍如何创建一个 S32DS 的工程,点亮开发板上的 LED 我们从官方提供的例程…

C++(20):多重继承与虚继承

多重继承 是指从多个直接基类中产生派生类的能力。多重继承的派生类继承了所有父类的属性。 多重继承 在派生类的派生列表中可以包含多个基类&#xff1a; class Bear : public zooAnimal { class Panda : public Bear, public Endangered{/* ...*/};每个基类包含一个可选的…

Android 大图显示优化方案-加载Gif 自定义解码器

基于Glide做了图片显示的优化&#xff0c;尤其是加载Gif图的优化&#xff0c;原生Glide加载Gif图性能较低。在原生基础上做了自定义解码器的优化&#xff0c;提升Glide性能 Glide加载大图和Gif 尤其是列表存在gif时&#xff0c;会有明显卡顿&#xff0c;cpu和内存占用较高&…

Android学习之路(13) Handler详解

1. 简介 Handler是一套 Android 消息传递机制,主要用于线程间通信。 用最简单的话描述&#xff1a; handler其实就是主线程在起了一个子线程&#xff0c;子线程运行并生成Message&#xff0c;Looper获取message并传递给Handler&#xff0c;Handler逐个获取子线程中的Message.…

RT-Thread 中断管理学习(二)

中断的底半处理 RTT不对中断服务程序所需要的处理时间做任何假设、限制&#xff0c;但如图其它实时操作系统或非实时操作系统一样&#xff0c;用户需要保证所有的中断服务程序在尽可能短的时间内完成&#xff08;中断服务程序在系统中相当于拥有最高的优先级&#xff0c;会抢占…

论文研读-SIMD系列-利用BMI指令进行选择下推

利用位操作指令BMI在列存中进行选择下推 Selection Pushdown in Column Stores using Bit Manipulation Instructions 列存能够提供高效的压缩能力&#xff0c;所以当前分析型数据库系统都基于列存储。然而&#xff0c;查询处理时&#xff0c;压缩会面临解码速率的挑战。以往研…

亚马逊产品流量上不去怎么办?亚马逊产品流量入口有哪些?

众所周知流量对于跨境卖家们是很重要的&#xff0c;这影响了你产品的曝光度和转化率&#xff0c;那么如果亚马逊产品流量上不去怎么办&#xff0c;亚马逊产品流量入口有哪些&#xff1f; 亚马逊产品流量上不去怎么办&#xff1f; 1、优化产品标题和关键词 产品标题和关键词是…

mojo初体验

目录标题 mojo初体验试用地址变量定义参数可变性和所有权Structures后续 mojo初体验 试用地址 https://www.modular.com/get-started 与python基础语法很相似。 变量定义 let定义不可变变量var定义可变变量 参数可变性和所有权 下面是一个基本的函数&#xff1a; fn add…