React重新渲染的触发机制及其优化策略

React是一个用于构建用户界面的JavaScript库,它的核心特点之一是使用虚拟DOMVirtual DOM)来实现高效的组件渲染。那组件重新渲染的机制是如何呢?基于这些机制,如果进行优化呢?

在这里插入图片描述

虚拟DOM是一个用JavaScript对象表示的DOM树,它可以在内存中快速地创建和修改,而不需要直接操作真实的DOMReact会根据组件的状态(state)和属性(props)来生成虚拟DOM,并与上一次的虚拟DOM进行比较,找出差异,然后将这些差异应用到真实的DOM上,从而更新用户界面。

公众号:Code程序人生,个人网站:https://creatorblog.cn

那么,React是如何知道什么时候需要重新渲染组件呢?

组件重新渲染的触发机制

一般来说,有以下四种情况会导致组件重新渲染:

组件状态(state)发生变化

当我们调用setState方法或者使用useState钩子(hook)来更新组件的状态时,React会自动重新渲染该组件及其子组件。

例如,下面的代码定义了一个简单的计数器组件,它使用useState钩子来管理计数值,并提供增加和减少的按钮。每次点击按钮时,都会调用setCount函数来更新计数值,从而触发组件的重新渲染。

import React, { useState } from "react";

function Counter() {
  // 使用useState钩子来创建一个状态变量count和一个更新函数setCount
  const [count, setCount] = useState(0);

  // 定义一个函数来增加计数值
  function handleIncrease() {
    // 调用setCount函数来更新计数值,传入一个函数作为参数,该函数接收上一次的计数值作为参数,并返回新的计数值
    setCount((prevCount) => prevCount + 1);
  }

  // 定义一个函数来减少计数值
  function handleDecrease() {
    // 调用setCount函数来更新计数值,传入一个函数作为参数,该函数接收上一次的计数值作为参数,并返回新的计数值
    setCount((prevCount) => prevCount - 1);
  }

  // 返回一个JSX元素,显示当前计数值,并提供增加和减少的按钮
  return (
    <div>
      <p>当前计数:{count}</p>
      <button onClick={handleIncrease}>增加</button>
      <button onClick={handleDecrease}>减少</button>
    </div>
  );
}

export default Counter;

组件属性(props)发生变化

当我们向组件传递新的属性值时,React会自动重新渲染该组件及其子组件。但是,这里有一个重要的细节:React并不是根据属性值本身是否变化来判断是否需要重新渲染,而是根据属性值的引用是否变化。

也就是说,如果我们传递了一个新创建的对象或数组作为属性值,即使它们的内容没有变化,也会触发重新渲染,因为它们的引用不同于之前的值。这也是为什么我们应该尽量避免在渲染函数中直接创建对象或数组作为属性值的原因。

例如,下面的代码定义了一个简单的列表组件,它接受一个数组作为属性值,并显示数组中的每个元素。在父组件中,我们每隔一秒就向列表组件传递一个新创建的数组,即使数组中的元素没有变化,也会导致列表组件重新渲染。

import React, { useState, useEffect } from "react";

// 一个简单的列表组件,接受一个数组作为属性值,并显示数组中的每个元素
function List({ items }) {
  console.log("List is rendering");
  return (
    <ul>
      {items.map((item) => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
}

// 一个简单的父组件,管理一个数组,并定时向列表组件传递新创建的数组
function App() {
  const [items, setItems] = useState(["a", "b", "c"]);

  // 使用useEffect钩子来在组件挂载后定时更新数组
  useEffect(() => {
    // 定义一个定时器,在每隔一秒后调用setItems函数来更新数组
    const timer = setInterval(() => {
      // 调用setItems函数来更新数组,传入一个新创建的数组作为参数,该数组与之前的数组内容相同
      setItems(["a", "b", "c"]);
    }, 1000);

    // 返回一个清理函数,在组件卸载前取消定时器
    return () => {
      clearInterval(timer);
    };
  }, []);

  console.log("App is rendering");
  return (
    <div>
      <h1>React重新渲染示例</h1>
      {/* 向列表组件传递数组作为属性值 */}
      <List items={items} />
    </div>
  );
}

export default App;

组件所依赖的上下文(context)发生变化

当我们使用useContext钩子或者contextType属性来订阅一个上下文时,如果该上下文的值发生变化,React会自动重新渲染订阅了该上下文的所有组件。

例如,下面的代码定义了一个简单的主题组件,它使用createContext函数来创建一个主题上下文,并提供一个切换主题的按钮。在子组件中,我们使用useContext钩子来订阅主题上下文,并根据主题值来显示不同的颜色。每次点击按钮时,都会调用setTheme函数来更新主题值,从而触发子组件的重新渲染。

import React, { useState, createContext, useContext } from "react";

// 使用createContext函数来创建一个主题上下文,传入一个默认值作为参数
const ThemeContext = createContext("light");

// 一个简单的主题组件,使用useState钩子来管理主题值,并提供一个切换主题的按钮
function ThemeProvider({ children }) {
  // 使用useState钩子来创建一个状态变量theme和一个更新函数setTheme
  const [theme, setTheme] = useState("light");

  // 定义一个函数来切换主题
  function toggleTheme() {
    // 调用setTheme函数来更新主题值,传入一个函数作为参数,该函数接收上一次的主题值作为参数,并返回新的主题值
    setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
  }

  // 返回一个JSX元素,使用ThemeContext.Provider组件来提供主题值,并显示切换主题的按钮和子组件
  return (
    <ThemeContext.Provider value={theme}>
      <button onClick={toggleTheme}>切换主题</button>
      {children}
    </ThemeContext.Provider>
  );
}

// 一个简单的子组件,使用useContext钩子来订阅主题上下文,并根据主题值来显示不同的颜色
function Child() {
  // 使用useContext钩子来获取主题上下文的值
  const theme = useContext(ThemeContext);

  // 返回一个JSX元素,根据主题值来设置样式,并显示当前主题
  return (
    <div style={{ color: theme === "light" ? "black" : "white" }}>
      当前主题:{theme}
    </div>
  );
}

// 一个简单的父组件,使用ThemeProvider组件来包裹子组件
function App() {
  return (
    <div>
      <h1>React重新渲染示例</h1>
      {/* 使用ThemeProvider组件来包裹子组件 */}
      <ThemeProvider>
        {/* 显示子组件 */}
        <Child />
      </ThemeProvider>
    </div>
  );
}

export default App;

组件所依赖的自定义钩子(custom hook)发生变化

当我们使用自定义钩子来封装一些逻辑或状态时,如果该钩子返回了一个新的值,React会自动重新渲染使用了该钩子的所有组件。

例如,下面的代码定义了一个简单的窗口大小钩子,它使用useStateuseEffect钩子来获取和更新窗口大小,并返回一个包含宽度和高度的对象。在组件中,我们使用这个自定义钩子来获取窗口大小,并显示在界面上。每次调整窗口大小时,都会触发自定义钩子返回一个新的对象,从而触发组件的重新渲染。

import React, { useState, useEffect } from "react";

// 定义一个自定义钩子,用于获取和更新窗口大小
function useWindowSize() {
  // 使用useState钩子来创建一个状态变量size和一个更新函数setSize
  const [size, setSize] = useState({
    // 初始化状态值为当前窗口的宽度和高度
    width: window.innerWidth,
    height: window.innerHeight,
  });

  // 使用useEffect钩子来在组件挂载后添加一个窗口大小变化的事件监听器,并在组件卸载前移除该监听器
  useEffect(() => {
    // 定义一个函数来处理窗口大小变化的事件
    function handleResize() {
      // 调用setSize函数来更新状态值,传入一个新创建的对象作为参数,该对象包含当前窗口的宽度和高度
      setSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }

    // 添加一个窗口大小变化的事件监听器,传入handleResize函数作为参数
    window.addEventListener("resize", handleResize);

    // 返回一个清理函数,在组件卸载前移除事件监听器
    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  // 返回状态值
  return size;
}

// 一个简单的组件,使用useWindowSize钩子来获取窗口大小,并显示在界面上
function App() {
  // 使用useWindowSize钩子来获取窗口大小
  const size = useWindowSize();

  // 返回一个JSX元素,显示当前窗口的宽度和高度
  return (
    <div>
      <h1>React重新渲染示例</h1>
      <p>当前窗口大小:{size.width} x {size.height}</p>
    </div>
  );
}

export default App;

如何避免不必要的重新渲染

以上四种情况都是必要的重新渲染,因为它们反映了组件内部或外部的数据变化,从而保证了用户界面与数据保持一致。

但是,在一些情况下,我们可能会遇到不必要的重新渲染,即组件没有任何数据变化,但仍然被重新渲染了。这可能会导致性能问题,特别是当组件很复杂或者很频繁地被重新渲染时。那么,如何避免不必要的重新渲染呢?有以下几种常用的优化策略:

React.memo

使用React.memo高阶组件来包裹函数式组件。这样可以让React在渲染组件之前先对比一下属性值是否有变化,如果没有变化,则跳过渲染。这可以避免因为父组件重新渲染而导致子组件也跟着重新渲染的情况。

例如,下面的代码定义了一个简单的计数器组件,它接受一个数字作为属性值,并显示该数字。在父组件中,我们使用useState钩子来管理一个数字,并提供一个增加的按钮。每次点击按钮时,都会调用setNumber函数来更新数字,从而触发父组件的重新渲染。

如果我们不使用React.memo来包裹计数器组件,则每次点击按钮时,计数器组件也会被重新渲染,即使它的属性值没有变化。如果我们使用React.memo来包裹计数器组件,则只有当它的属性值变化时,才会触发它的重新渲染。

import React, { useState } from "react";

// 一个简单的计数器组件,接受一个数字作为属性值,并显示该数字
function Counter({ number }) {
  console.log("Counter is rendering");
  return <p>当前数字:{number}</p>;
}

// 使用React.memo包裹计数器组件,使其只在属性值变化时才重新渲染
const MemoizedCounter = React.memo(Counter);

// 一个简单的父组件,使用useState钩子来管理一个数字,并提供一个增加的按钮
function App() {
  // 使用useState钩子来创建一个状态变量number和一个更新函数setNumber
  const [number, setNumber] = useState(0);

  // 定义一个函数来增加数字
  function handleIncrease() {
    // 调用setNumber函数来更新数字,传入一个函数作为参数,该函数接收上一次的数字作为参数,并返回新的数字
    setNumber((prevNumber) => prevNumber + 1);
  }

  console.log("App is rendering");
  return (
    <div>
      <h1>React重新渲染示例</h1>
      <button onClick={handleIncrease}>增加</button>
      {/* 向计数器组件传递数字作为属性值 */}
      <MemoizedCounter number={number} />
    </div>
  );
}

export default App;

useMemo

使用useMemo钩子来缓存计算结果。这样可以让我们只在依赖项发生变化时才重新计算结果,而不是每次渲染都计算。这可以避免因为计算开销大而导致渲染时间过长的情况。

例如,下面的代码定义了一个简单的斐波那契数列组件,它接受一个数字作为属性值,并显示该数字对应的斐波那契数。在父组件中,我们使用useState钩子来管理一个数字,并提供一个增加和减少的按钮。每次点击按钮时,都会调用setNumber函数来更新数字,从而触发父组件和子组件的重新渲染。

如果我们不使用useMemo钩子来缓存斐波那契数的计算结果,则每次重新渲染都会重新执行斐波那契数的递归函数,这会消耗很多时间和资源。如果我们使用useMemo钩子来缓存斐波那契数的计算结果,则只有当依赖项变化时才会重新执行斐波那契数的递归函数。

import React, { useState, useMemo } from "react";

// 定义一个函数来计算斐波那契数,使用递归的方式
function fibonacci(n) {
  // 如果n小于等于1,则返回n
  if (n <= 1) {
    return n;
  }
  // 否则,返回前两项的和
  return fibonacci(n - 1) + fibonacci(n - 2);
}

// 一个简单的斐波那契数列组件,接受一个数字作为属性值,并显示该数字对应的斐波那契数
function Fibonacci({ number }) {
  // 使用useMemo钩子来缓存斐波那契数的计算结果,传入一个函数作为参数,该函数返回斐波那契数的值,以及一个数组作为依赖项,该数组包含了影响计算结果的变量
  const result = useMemo(() => {
    // 调用fibonacci函数来计算斐波那契数的值
    return fibonacci(number);
  }, [number]); // 依赖项是number,只有当number变化时才会重新计算结果

  console.log("Fibonacci is rendering");
  return <p>{number}项斐波那契数是:{result}</p>;
}

// 一个简单的父组件,使用useState钩子来管理一个数字,并提供一个增加和减少的按钮
function App() {
  // 使用useState钩子来创建一个状态变量number和一个更新函数setNumber
  const [number, setNumber] = useState(0);

  // 定义一个函数来增加数字
  function handleIncrease() {
    // 调用setNumber函数来更新数字,传入一个函数作为参数,该函数接收上一次的数字作为参数,并返回新的数字
    setNumber((prevNumber) => prevNumber + 1);
  }

  // 定义一个函数来减少数字
  function handleDecrease() {
    // 调用setNumber函数来更新数字,传入一个函数作为参数,该函数接收上一次的数字作为参数,并返回新的数字
    setNumber((prevNumber) => prevNumber - 1);
  }

  console.log("App is rendering");
  return (
    <div>
      <h1>React重新渲染示例</h1>
      <button onClick={handleIncrease}>增加</button>
      <button onClick={handleDecrease}>减少</button>
      {/* 向斐波那契数列组件传递数字作为属性值 */}
      <Fibonacci number={number} />
    </div>
  );
}

export default App;

useCallback

使用useCallback钩子来缓存函数。这样可以让我们只在依赖项发生变化时才重新创建函数,而不是每次渲染都创建。这可以避免因为传递了新的函数作为属性值而导致子组件重新渲染的情况。

例如,下面的代码定义了一个简单的计数器组件,它接受两个函数作为属性值,并提供增加和减少的按钮。在父组件中,我们使用useState钩子来管理一个数字,并定义两个函数来修改数字。每次点击按钮时,都会调用相应的函数来更新数字,从而触发父组件和子组件的重新渲染。

如果我们不使用useCallback钩子来缓存这两个函数,则每次重新渲染都会创建新的函数,并传递给子组件,从而触发子组件的重新渲染。如果我们使用useCallback钩子来缓存这两个函数,则只有当依赖项变化时才会重新创建函数,并传递给子组件。

import React, { useState, useCallback } from "react";

// 一个简单的计数器组件,接受两个函数作为属性值,并提供增加和减少的按钮
function Counter({ onIncrease, onDecrease }) {
  console.log("Counter is rendering");
  return (
    <div>
      <button onClick={onIncrease}>增加</button>
      <button onClick={onDecrease}>减少</button>
    </div>
  );
}

// 一个简单的父组件,使用useState钩子来管理一个数字,并定义两个函数来修改数字
function App() {
  // 使用useState钩子来创建一个状态变量number和一个更新函数setNumber
  const [number, setNumber] = useState(0);

  // 使用useCallback钩子来缓存增加数字的函数,传入一个函数作为参数,该函数返回增加数字的操作,以及一个数组作为依赖项,该数组包含了影响函数结果的变量
  const handleIncrease = useCallback(() => {
    // 调用setNumber函数来更新数字,传入一个函数作为参数,该函数接收上一次的数字作为参数,并返回新的数字
    setNumber((prevNumber) => prevNumber + 1);
  }, []); // 依赖项是空数组,表示该函数不依赖于任何外部变量,只在组件挂载时创建一次

  // 使用useCallback钩子来缓存减少数字的函数,传入一个函数作为参数,该函数返回减少数字的操作,以及一个数组作为依赖项,该数组包含了影响函数结果的变量
  const handleDecrease = useCallback(() => {
    // 调用setNumber函数来更新数字,传入一个函数作为参数,该函数接收上一次的数字作为参数,并返回新的数字
    setNumber((prevNumber) => prevNumber - 1);
  }, []); // 依赖项是空数组,表示该函数不依赖于任何外部变量,只在组件挂载时创建一次

  console.log("App is rendering");
  return (
    <div>
      <h1>React重新渲染示例</h1>
      <p>当前数字:{number}</p>
      {/* 向计数器组件传递缓存后的函数作为属性值 */}
      <Counter onIncrease={handleIncrease} onDecrease={handleDecrease} />
    </div>
  );
}

export default App;

React.PureComponent/shouldComponentUpdate

使用React.PureComponent或者shouldComponentUpdate方法来优化类组件。这样可以让React在渲染组件之前先对比一下状态和属性值是否有变化,如果没有变化,则跳过渲染。这与React.memo类似,但是适用于类组件。

例如,下面的代码定义了一个简单的计数器组件,它继承自React.PureComponent类,并使用this.statethis.setState方法来管理计数值,并提供增加和减少的按钮。在父组件中,我们使用useState钩子来管理一个数字,并提供一个增加的按钮。

每次点击按钮时,都会调用setNumber函数来更新数字,从而触发父组件的重新渲染。如果我们不继承自React.PureComponent类,则每次点击按钮时,计数器组件也会被重新渲染,即使它的状态和属性值没有变化。如果我们继承自React.PureComponent类,则只有当它的状态或属性值变化时,才会触发它的重新渲染。

import React, { useState } from "react";

// 一个简单的计数器组件,继承自React.PureComponent类,并使用this.state和this.setState方法来管理计数值,并提供增加和减少的按钮
class Counter extends React.PureComponent {
  // 定义一个构造函数,接受一个属性对象作为参数,并调用父类的构造函数
  constructor(props) {
    super(props);

    // 初始化状态对象,包含一个计数值
    this.state = {
      count: 0,
    };
  }

  // 定义一个方法来增加计数值
  handleIncrease = () => {
    // 调用this.setState方法来更新状态对象,传入一个函数作为参数,该函数接收上一次的状态对象作为参数,并返回新的状态对象
    this.setState((prevState) => ({
      // 返回新的状态对象,将计数值加一
      count: prevState.count + 1,
    }));
  };

  // 定义一个方法来减少计数值
  handleDecrease = () => {
    // 调用this.setState方法来更新状态对象,传入一个函数作为参数,该函数接收上一次的状态对象作为参数,并返回新的状态对象
    this.setState((prevState) => ({
      // 返回新的状态对象,将计数值减一
      count: prevState.count - 1,
    }));
  };

  // 定义一个渲染方法,返回一个JSX元素,显示当前计数值,并提供增加和减少的按钮
  render() {
    console.log("Counter is rendering");
    return (
      <div>
        <p>当前计数:{this.state.count}</p>
        <button onClick={this.handleIncrease}>增加</button>
        <button onClick={this.handleDecrease}>减少</button>
      </div>
    );
  }
}

// 一个简单的父组件,使用useState钩子来管理一个数字,并提供一个增加的按钮
function App() {
  // 使用useState钩子来创建一个状态变量number和一个更新函数setNumber
  const [number, setNumber] = useState(0);

  // 定义一个函数来增加数字
  function handleIncrease() {
    // 调用setNumber函数来更新数字,传入一个函数作为参数,该函数接收上一次的数字作为参数,并返回新的数字
    setNumber((prevNumber) => prevNumber + 1);
  }

  console.log("App is rendering");
  return (
    <div>
      <h1>React重新渲染示例</h1>
      <button onClick={handleIncrease}>增加</button>
      {/* 向计数器组件传递数字作为属性值 */}
      <Counter number={number} />
    </div>
  );
}

export default App;

key

使用key属性来优化列表渲染。这样可以让React在渲染列表时能够识别出每个列表项的唯一标识,从而避免不必要的创建和销毁。这可以提高列表渲染的性能和稳定性。

例如,下面的代码定义了一个简单的待办事项列表组件,它接受一个数组作为属性值,并显示数组中的每个元素。在父组件中,我们使用useState钩子来管理一个数组,并提供一个添加和删除的按钮。每次点击按钮时,都会调用相应的函数来更新数组,从而触发父组件和子组件的重新渲染。

如果我们不使用key属性来给每个列表项分配一个唯一标识,则每次重新渲染都会导致所有的列表项被重新创建和销毁,这会浪费很多时间和资源。如果我们使用key属性来给每个列表项分配一个唯一标识,则只有当列表项增加或减少时才会触发创建和销毁,而当列表项顺序变化时则只会触发移动,这会节省很多时间和资源。

import React, { useState } from "react";

// 一个简单的待办事项列表组件,接受一个数组作为属性值,并显示数组中的每个元素
function TodoList({ items }) {
  console.log("TodoList is rendering");
  return (
    <ul>
      {items.map((item) => (
        // 使用key属性来给每个列表项分配一个唯一标识,这里我们使用item.id作为标识
        <li key={item.id}>{item.text}</li>
      ))}
    </ul>
  );
}

// 一个简单的父组件,使用useState钩子来管理一个数组,并提供一个添加和删除的按钮
function App() {
  // 使用useState钩子来创建一个状态变量items和一个更新函数setItems
  const [items, setItems] = useState([
    // 初始化状态值为一个包含三个对象的数组,每个对象包含一个id和一个text
    { id: 1, text: "学习React" },
    { id: 2, text: "写博客" },
    { id: 3, text: "做运动" },
  ]);

  // 定义一个函数来添加待办事项
  function handleAdd() {
    // 调用setItems函数来更新状态值,传入一个函数作为参数,该函数接收上一次的状态值作为参数,并返回新的状态值
    setItems((prevItems) => [
      // 返回新的状态值,将上一次的状态值复制一份,并在末尾添加一个新的对象,该对象包含一个随机生成的id和一个固定的text
      ...prevItems,
      { id: Math.random(), text: "新待办事项" },
    ]);
  }

  // 定义一个函数来删除待办事项
  function handleDelete() {
    // 调用setItems函数来更新状态值,传入一个函数作为参数,该函数接收上一次的状态值作为参数,并返回新的状态值
    setItems((prevItems) => [
      // 返回新的状态值,将上一次的状态值复制一份,并删除第一个元素
      ...prevItems.slice(1),
    ]);
  }

  console.log("App is rendering");
  return (
    <div>
      <h1>React重新渲染示例</h1>
      <button onClick={handleAdd}>添加</button>
      <button onClick={handleDelete}>删除</button>
      {/* 向待办事项列表组件传递数组作为属性值 */}
      <TodoList items={items} />
    </div>
  );
}

export default App;

总结

React是一个用于构建用户界面的JavaScript库,它使用虚拟DOM来高效地渲染组件。组件的状态(state)、属性(props)、上下文(context)和自定义钩子(custom hook)的变化会触发重新渲染。有时,我们需要避免不必要的重新渲染,以提高性能和稳定性。我们可以使用以下几种优化策略:

  • 使用React.memouseMemouseCallback来缓存函数式组件、计算结果和函数,使其只在依赖项变化时才重新渲染或创建。
  • 使用React.PureComponent或者shouldComponentUpdate方法来优化类组件,使其只在状态或属性值变化时才重新渲染。
  • 使用key属性来优化列表渲染,使React能够识别每个列表项的唯一标识,从而避免不必要的创建和销毁。

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

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

相关文章

"科技与狠活"企业级无代码开发MES系统,一周实现数字化

随着科技的不断发展&#xff0c;企业级无代码开发平台成为了一种新型的解决方案&#xff0c;能够有效降低软件开发门槛&#xff0c;提升开发效率。在制造业领域&#xff0c;MES系统&#xff08;Manufacturing Execution System&#xff09;作为一种关键的生产管理工具&#xff…

C# 全局响应Ctrl+Alt+鼠标右键

一、简述 某些应用&#xff0c;我们希望全局自定义热键。按键少了会和别的应用程序冲突&#xff0c;按键多了可定用户操作不变。因此我计划左手用CtrlAlt&#xff0c;右手用鼠标右键呼出我自定义的菜单。 我使用键盘和鼠标事件进行简单测试&#xff08;Ctrl鼠标右键&#xff…

[SQL系列] 从头开始学PostgreSQL 自增 权限和时间

[SQL系列] 从头开始学PostgreSQL 事务 锁 子查询_Edward.W的博客-CSDN博客https://blog.csdn.net/u013379032/article/details/131841058上一篇介绍了事务&#xff0c;锁&#xff0c;子查询 事务有点像是原子操作&#xff0c;需要有完整性&#xff0c;要么全都完成了&#xff…

2023年深圳杯数学建模A题影响城市居民身体健康的因素分析

2023年深圳杯数学建模 A题 影响城市居民身体健康的因素分析 原题再现&#xff1a; 以心脑血管疾病、糖尿病、恶性肿瘤以及慢性阻塞性肺病为代表的慢性非传染性疾病&#xff08;以下简称慢性病&#xff09;已经成为影响我国居民身体健康的重要问题。随着人们生活方式的改变&am…

flutter开发实战-RepaintBoundary实现Widget截图功能

flutter开发实战-RepaintBoundary实现Widget截图功能 在开发中&#xff0c;遇到需要使用截图&#xff0c;像iOS可以截图UIView获取到UIImage&#xff0c;在flutter中可以使用RepaintBoundary实现截图功能 相机拍摄的图片&#xff1a; RepaintBoundary截图后的图片 一、Re…

Docker 全栈体系(七)

Docker 体系&#xff08;高级篇&#xff09; 五、Docker-compose容器编排 1. 是什么 Compose 是 Docker 公司推出的一个工具软件&#xff0c;可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml&#xff0c;写好多个容器之间的调…

python selenium爬虫自动登录实例

拷贝地址&#xff1a;python selenium爬虫自动登录实例_python selenium登录_Ustiniano的博客-CSDN博客 一、概述 我们要先安装selenium这个库&#xff0c;使用pip install selenium 命令安装&#xff0c;selenium这个库相当于机器模仿人的行为去点击浏览器上的元素&#xff0…

测试技术之测试用例质量的评估

第一&#xff0c;凭证测试用例的方式评估其品质&#xff0c;主要搜罗&#xff1a; 1)测试用例与需要规格剖析中需要条款的可追溯性&#xff0c;好比&#xff1a;咱们要求每一个需要条款至少有1个测试用例与之对于应。目的是为了评估测试的需要拆穿困绕率&#xff0c;以及合成需…

抖音seo源码开发源代码开发技术分享

一、 抖音SEO源码开发&#xff0c;需要掌握以下技术&#xff1a; 抖音API接口&#xff1a;抖音提供了丰富的API接口&#xff0c;包括用户信息、视频信息、评论信息等。 数据爬取技术&#xff1a;通过抓包分析抖音接口的数据结构&#xff0c;可以使用Python等编程语言编写爬虫程…

【低代码专题方案】iPaaS运维方案,助力企业集成平台智能化高效运维

01 场景背景 随着IT行业的发展和各家企业IT建设的需要&#xff0c;信息系统移动化、社交化、大数据、系统互联、数据打通等需求不断增多&#xff0c;企业集成平台占据各个企业领域&#xff0c;成为各业务系统数据传输的中枢。 集成平台承接的业务系统越多&#xff0c;集成平台…

Practice1|1207. 独一无二的出现次数、1365. 有多少小于当前数字的数字、941. 有效的山脉数组

1207. 独一无二的出现次数 1.题目&#xff1a; 给你一个整数数组 arr&#xff0c;请你帮忙统计数组中每个数的出现次数。 如果每个数的出现次数都是独一无二的&#xff0c;就返回 true&#xff1b;否则返回 false。 示例 1&#xff1a; 输入&#xff1a;arr [1,2,2,1,1,3…

FPGA-DFPGL22学习7-gpio

系列文章目录 FPGA-DFPGL22学习6-led 文章目录 系列文章目录前言一、原理图1&#xff09;key2&#xff09;beeptouch端口对应1)key2)beeptouch 二、程序设计1)KEY2)beeptouch 三、程序编写1.KEY代码&#xff1a;2.beeptouch代码&#xff1a; 结论 前言 和原子哥一起学习FPGA …

JAVA面试总结-Redis篇章(四)——双写一致性

JAVA面试总结-Redis篇章&#xff08;四&#xff09;——双写一致性 问&#xff1a;redis 做为缓存&#xff0c;mysql的数据如何与redis进行同步呢&#xff1f;第一种情况&#xff0c;如果你的项目一致性要求高的话 采用以下逻辑我们应该先删除缓存&#xff0c;再修改数据库&…

「深度学习之优化算法」(十八)头脑风暴算法

1. 头脑风暴算法简介 (以下描述,均不是学术用语,仅供大家快乐的阅读)   可能大家对“头脑风暴”这个词不怎么熟,毕竟是外来词汇,其大概含义就是分组讨论,畅所欲言。   头脑风暴算法(Brain Storm Optimization)是根据人们进行“头脑风暴”讨论困难问题的解决方案的过…

Spring数据源

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;JavaEE、Spring 目录 1、简介2、作用3、开发步骤3.1、导入坐标3.2、创建对象c3p0druid提取jdbc.properties读取配…

【Git】

学习来自于&#xff1a; 女朋友乱用Git&#xff0c;差点把我代码删了。。。 一些常用的Git 知识点整理 关于Git这一篇就够了 Git基本命令大全 30分钟精通Git&#xff0c;学不会来找我 Git 版本管理 | 莫烦PYTHON Git 代码版本管理教程 文章目录 【前言】集中式与分布式的…

【微服务系统设计】系统设计基础:速率限制器

什么是速率限制器&#xff1f; 速率限制是指防止操作的频率超过定义的限制。在大型系统中&#xff0c;速率限制通常用于保护底层服务和资源。速率限制一般在分布式系统中作为一种防御机制&#xff0c;使共享资源能够保持可用性。 速率限制通过限制在给定时间段内可以到达您的 A…

分布式光伏并网防孤岛保护装置AM5SE-IS

分布式光伏并网防孤岛保护装置AM5SE-IS 应用场景 防孤岛原理&#xff1a;防孤岛保护装置检测到并网点有逆功率、频率突变、 等异常数据时&#xff0c;即发生孤岛现象时&#xff0c;装置可配合断路器快速切除并网点&#xff0c;使本站与电网侧快速脱离&#xff0c;保证整个电站…

国内疫情地图和省级疫情地图

基础地图演示 from pyecharts.charts import Mapfrom pyecharts.options import VisualMapOpts map Map() data [ ("北京", 99), ("上海", 199), ("湖南", 299), ("台湾", 199), ("安徽", 299), ("广州", 399…

git的clone,上传与upstream同步

文章目录 clone同步 clone clone他人项目&#xff0c;git到自己的项目 rm -rf .git .git存放原始项目的日志信息&#xff0c;这里需要添加自己的日志信息&#xff0c;需要删除重写。也可手动删除 git init 初始化文件&#xff0c;依据本地日志信息生产.git文件 git add 目标文…