React筆記-Hooks(九)

来源:https://www.cnblogs.com/SpicyPeper/archive/2023/05/22/17421590.html
-Advertisement-
Play Games

# React筆記-Hooks(九) ## Hooks ### 概念 >React Hooks 的意思是 組件儘量寫成純函數 如果需要外部功能和副作用 就用鉤子把外部代碼"鉤"進來 ### 函數組件和類組件區別 >- 函數組件沒有狀態(state) 類組件有 >- 函數組件沒有生命周期 類組件有(掛 ...


React筆記-Hooks(九)

Hooks

概念

React Hooks 的意思是 組件儘量寫成純函數 如果需要外部功能和副作用 就用鉤子把外部代碼"鉤"進來

函數組件和類組件區別

  • 函數組件沒有狀態(state) 類組件有
  • 函數組件沒有生命周期 類組件有(掛載-更新-銷毀)
  • 函數組件沒有this 類組件有
  • 函數組件更適合做UI展示 類組件更適合做複雜的業務邏輯組件

為什麼純函數組件逐漸取代類組件

React團隊希望 組件不要變成複雜的容器 最好只是數據流的管道 開發者根據需要 組合管道即可

Hooks用法

useState() 狀態鉤子

純函數組件沒有狀態,useState()用於設置和使用組件的狀態屬性

// Hooks是無狀態的 所以用這種方式替換類組件中的狀態(state)
const [state, setState] = useState(initialValue);
// state:初始的狀態屬性,指向狀態當前值,類似this.state
// setState:修改狀態屬性值的函數,用來更新狀態,小駝峰命名
// setState((currentState) => {]})可以傳入一個函數 函數接收一個參數 用於存放當前state
// initialValue:狀態的初始值,該值會賦給state

import { useState } from 'react';



function LearnHooks () {

    let a = 1;
    const [num, setNum] = useState(0);
    const [name, setName] = useState([{name : 'bob', age : 18}, {name : 'sam', age : 20}, {name : 'kitty', age : 22}]);

    const addNum = () => {
        setNum(num + 1)
        // setNum是非同步操作 所以console.log(num)輸出的是更新前的值
        console.log(num)
        a += 1;
        // 這裡a永遠輸出為2
        // 原因是hooks重新渲染是自調用 每次都會重新把a設為1 然後執行 a + 1
        console.log(a)
    }

    console.log('LearnHooks渲染了')
    return (
        <div>
            <h1>學習hooks的userState</h1>
            <div>當前num : {num}</div>
            <button onClick={() => addNum()}>num + 1</button>
            <div>{name.map((item) => {
                    return <div key={item.name}>name : {item.name}, age : {item.age}</div>
                })}
            </div>
            <input type="text" onChange={ ({target : {value}}) => setName([{name : value}])}/>
        </div>
    );
    
}

export default LearnHooks;

useEffect() 副作用鉤子

可以實現特定的功能 如非同步請求

useEffect(() => {
    // 回調函數,其中是要進行的非同步操作代碼
    return () => {}
    // useEffect中的return語句可以用於清除effect產生的副作用。當組件卸載時,React會執行return語句中的函數,以清除effect產生的副作用。例如,如果在useEffect中訂閱了一個事件,那麼在return語句中取消訂閱可以避免記憶體泄漏。
}, [array])
// [array]:useEffect執行的依賴,當該數組的值發生改變時,回調函數中的代碼就會被執行
// 如果[array]省略,則表示不依賴,在每次渲染時回調函數都會執行
// 如果[array]是空數組,即useEffect第二項為[],表示只執行一次

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

function hook() {

  const [num, setNum] = useState(1)
  /**
   * 第一個參數是回調函數
   * 第二個參數是依賴項
   * 每次num變化時都會變化
   * 
   * 註意初始化的時候,也會調用一次
   */
  useEffect(() => {
    console.log("每次num,改變我才會觸發")
  }, [num])


  return (
    <div>
      <button onClick={() => setNum(num + 1)}>+1</button>
      <div>你好,react hook{num}</div>
    </div>
  );
}

export default hook;

useLayoutEffect()

useLayoutEffect是React提供的一個Hook,與useEffect功能類似,但在組件更新DOM前執行,而不是之後。

與useEffect不同的是,useLayoutEffect會阻塞瀏覽器渲染,並立即同步執行副作用函數。這可以確保使用組件的代碼看到的是最新的DOM佈局,因為它們在組件掛載或更新時都會在渲染通道中優先處理。

// useLayoutEffect接收兩個參數:一個副作用函數和一個依賴項數組。副作用函數中可以進行DOM操作、計算佈局等任務,並且可以通過返回一個清除函數來清理副作用產生的任何資源。

useLayoutEffect(() => { 副作用函數執行邏輯 }, [ 依賴項 ])

// 1. 編寫副作用函數:useLayoutEffect需要傳遞一個函數作為參數,該函數稱為副作用函數。在這個函數里,你可以訪問到DOM、執行非同步操作或計算等其它操作,並考慮它們的收尾工作。當組件的props或state發生變化時,都將重新運行該函數。
import { useLayoutEffect } from 'react';

function useMyLayoutEffect() {
  // 執行DOM相關操作
  return () => {
    // 清理工作
  };
}


// 2. 將useLayoutEffect掛載到組件:要在組件中使用useLayoutEffect這個函數,只需要調用它即可,並把上一步編寫的副作用函數作為第一個參數。

function MyComponent() {

  useLayoutEffect(useMyLayoutEffect, []);

  return <div>Hello, world!</div>;

}


// 給useLayoutEffect傳遞依賴項數組:和useEffect一樣,useLayoutEffect的第二個參數是一個數組,其中包含在副作用函數中需要被“監視”的任何變數。當其中的變數發生更改時,useLayoutEffect將重新運行其副作用函數。

function MyComponent({ name }) {

  useLayoutEffect(() => {

    console.log(`MyComponent is mounted: ${name}`);

  }, [name]);

  return <div>Hello, {name}!</div>;
  
}

useContext() 共用狀態鉤子

可以共用狀態,作用是進行狀態的分發,避免了使用Props進行數據的傳遞

// 第一步:創建全局的Context
const AppContext = React.createContext([初始化參數])

// 第二步:通過全局的Context進行狀態值的共用
<AppContext.Provider value={{ 屬性名: 值 }}>
    <其他組件1 />
    <其他組件2 />
</AppContext>

// 第三步:使用context
const context = useContext(AppContext);
{context.name}

// 在 App.js 文件中
import React, { createContext, useState } from 'react';
import Child from './Child';

export const MyContext = createContext();

function App() {
  const [count, setCount] = useState(0);

  return (
    <MyContext.Provider value={{ count, setCount }}>
      <div>
        <h1>Count: {count}</h1>
        <button onClick={() => setCount(count + 1)}>Increment</button>
        <Child />
      </div>
    </MyContext.Provider>
  );
}

// 在 Child.js 文件中
import React, { useContext } from 'react';
import { MyContext } from './App';

function Child() {
  const { count, setCount } = useContext(MyContext);

  return (
    <div>
      <h2>Child Component</h2>
      <h3>Count: {count}</h3>
      <button onClick={() => setCount(count - 1)}>Decrement</button>
    </div>
  );
}

useMemo() 記憶鉤子(值)

useMemo是React中的一個hook,用於優化組件的性能。它的作用是緩存函數的返回值,只有當依賴項發生變化時才重新計算。這樣可以避免在每次渲染時都重新計算函數的返回值,從而提高組件的性能。

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

// 第一個參數是一個回調函數,用於計算需要緩存的值
// 第二個參數是一個數組,用於指定依賴項。只有當依賴項發生變化時,才會重新計算memoizedValue的值。

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

function MyComponent() {
  const { a, setA } = useState(1);
  const result = useMemo(() => {
    // 只有當a發生變化時才會重新計算。這樣可以避免在每次其他渲染時都重新計算結果,提高組件的性能
    return a * 2;
  }, [a]);

  const add = () => {
    setA(a + 1)
  }

  return (
    <div>
      <div>{result}</div>
      <button onClick={() => add()}>a+1</button>
    </div>
  );
}

useCallback() 記憶鉤子(函數)

useCallback是React中的一個Hook函數,用於優化函數組件的性能。它的作用是返回一個記憶化的回調函數,當依賴項發生變化時才會重新生成新的回調函數。這樣可以避免在每次渲染時都創建新的回調函數,從而提高組件的性能。

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

// 第一個參數是回調函數
// 第二個參數是依賴項數組。當依賴項數組中的任意一個值發生變化時,useCallback會重新生成新的回調函數。如果依賴項數組為空,則每次渲染都會返回同一個回調函數。


// 需要註意的是,useCallback返回的是一個記憶化的回調函數,而不是一個普通的函數。因此,如果需要在組件外部使用該回調函數,需要將其作為props傳遞給子組件。

// 舉例:使用useCallback優化組件性能

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

function MyComponent() {
  const [count, setCount] = useState(0);

  // 普通的回調函數
  const handleClick = () => {
    setCount(count + 1);
  };

  // 使用useCallback優化的回調函數
  const handleClickMemoized = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>普通的回調函數</button>
      <button onClick={handleClickMemoized}>使用useCallback優化的回調函數</button>
    </div>
  );
}

export default MyComponent;

useReducer() 行為鉤子

useReducer是React中一個狀態管理的Hooks,用於處理複雜的組件狀態邏輯。它和useState類似,都是用於管理組件狀態的,但是useReducer可以更好地處理複雜的狀態邏輯,尤其是在多個狀態相互影響的情況下會更加方便和清晰。


// 1. 定義初始狀態(initial state)和reducer函數。reducer函數的作用是根據當前的狀態和操作類型(action)來返回新的狀態值。

const initialState = {
  count: 0,
};

function reducer(state, action) {
  switch (action.type) {
    case 'ADD':
      return { count: state.count + 1 };
    case 'SUB':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}


// 2. 在組件中使用useReducer Hook,傳入reducer函數和initial state參數,獲取當前的state值和dispatch函數。

import React, { useReducer } from 'react';

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <h2>Counter: {state.count}</h2>
      <button onClick={() => dispatch({ type: 'ADD' })}>+</button>
      <button onClick={() => dispatch({ type: 'SUB' })}>-</button>
    </div>
  );
}

useRef() 保存引用值

useRef是React中的一個hook,用於創建一個可變的引用,類似於在類組件中使用的this.refs。與useState不同,useRef返回一個可變的值,而不會觸發重新渲染組件。

useRef可以用於保存任何可變值,例如DOM元素的引用、定時器的標識符、上一個渲染周期的狀態等。它還提供了一個.current屬性來訪問保存的值。

使用場景

  1. 獲取DOM元素的引用

  2. 保存上一個渲染周期的狀態

  3. 在useEffect中訪問最新的props和state值

  4. 保存定時器的標識符,以便在組件卸載時清除


// useRef創建的ref對象與組件生命周期不相關,因此它不會在調用setState或props更新時自動更新,ref改變取決於使用它的具體方式

const ref = useRef()

// 因為hooks重新渲染其實是組件的自調用,所以我們不能在組件中直接定義一個值,let a = 1 或 const arr = []都是錯誤的,此時我們使用useRef來保存和訪問持久性數據

useImperativeHandle()

useImperativeHandle是React Hook中的一個函數,用於在使用ref時,向父組件暴露子組件的方法或屬性。它可以覆蓋預設情況下通過ref自動公開該組件實例的方式,從而更加精準的控制哪些內容公開給父組件。

useImperativeHandle接受兩個參數:ref對象和一個callback函數。callback函數應該返回包含想要掛載到ref上的任何公共方法或屬性的對象。當父組件從ref調用該方法或訪問該屬性時,callback函數定義的邏輯將被執行。


// 1. 在子組件中使用forwardRef高階組件轉發ref,以在父組件中獲得對子組件的引用。

import React, { forwardRef } from 'react';

const Child = forwardRef((props, ref) => {
  // 組件...
});


// 2. 使用useImperativeHandle Hook,將可供父組件訪問的方法或屬性包裝在一個callback函數中,並將該函數作為useImperativeHandle的第二個參數傳遞

import React, { forwardRef, useImperativeHandle } from 'react';

const Child = forwardRef((props, ref) => {
  const someMethod = () => {
    console.log('Hello from the child component');
  };

  useImperativeHandle(ref, () => ({
    someMethod,
  }));

  return <div>...</div>;
});

export default Child;


// 3. 在父組件中使用ref來調用從子組件暴露的方法

import React, { useRef } from 'react';
import Child from './Child';

function Parent() {
  const childRef = useRef(null);

  const handleClick = () => {
    // 調用子組件中公開的 someMethod 方法
    childRef.current.someMethod();
  };

  return (
    <div>
      <button onClick={handleClick}>調用子組件方法</button>
      <Child ref={childRef} />
    </div>
  );
}

其他

Immutable Data(不可變數據)

解決的問題

在 js 中,對象都是引用類型,在按引用傳遞數據的場景中,會存在多個變數指向同一個記憶體地址的情況,如果有多個代碼塊同時更改這個引用,就會產生競態

實現的原理

Persistent Data Structure(持久化數據結構):用一種數據結構來保存數據。當數據被修改時,會返回一個對象,但是新的對象會儘可能的利用之前的數據結構而不會對記憶體造成浪費,也就是使用舊數據創建新數據時,要保證舊數據同時可用且不變,同時為了避免 deepCopy把所有節點都複製一遍帶來的性能損耗,Immutable 使用了 Structural Sharing(結構共用)

redux / flux

// redux / flux 要求採用返回新對象的形式,來觸發數據更新、re-render,一般推薦的做法就是採用對象解構的方式。如果 state 對象巨大(註意:對象巨大),在結構、拷貝 state 的過程中,耗時會較長。

return {
  ...state,
  settings: {
    ...state.settings,
    profile:{
      ...state.settings.profile,
      darkmode: true,
    }
  }
}

immer

immer中文網址


// 開源庫實現思路:原始對象先做了一層 Proxy 代理,得到 draftState 傳遞給 function。function(帶副作用) 直接更改 draftState,最後 produce 返回新的對象

// 安裝
npm install immer

//使用
import React, { useState } from "react";
import produce from "immer";


export default function App() {
  const [list, setList] = useState([1, 2, 3]);

  const addMutable = () => {
    list.push("新數據");
    setList(list);
  };

  const addImmutable = () => {
    /**
     * 第一個參數是要代理的數據
     * 第二個參數是一個函數
     */
    const newVal = produce(list, draft => {
      /**
       * draft 相當於 list
       * 在這個方法裡面,可以直接修改draft,註意draft也只能在這個方法裡面修改
       * 不需要返回值,immer內部已經幫我處理好了
       */
      draft.push('新數據')
    })
    console.log(newVal)
    setList(newVal);
  };

  return (
    <div className="App">
      <button onClick={addMutable}>已可變的方式添加</button>
      <button onClick={addImmutable}>已不可變的方式添加</button>
      {list.map((item, index) => (<li key={index}>{item}</li>))}
    </div>
  );
}

函數組件傳值

hooks直接通過props傳值

//父組件中在子組件標簽上定義屬性
import 子組件
<Son 屬性={值}></Son>

// 子組件接收父組件中傳遞屬性
props.屬性
父傳子

// 父組件
import { useState } from 'react'
import Son from './son'

function Father() {


  const [data, setData] = useState(0)

  return (
    <div>
      <Son
      {/*通過定義屬性傳值*/}
      name = 'bob' d = {data}
      ></Son>
      <button onClick={() => setData(data + 1)}>+1</button>
    </div>
  )

}

export default Father


// 子組件
import { useState } from 'react'


function Son (props) {

  return (
    <div>
      <div>{props.name}</div>
      <div>{props.d}</div>
    </div>
  )
}



export default Son

子傳父

// 父組件
import { useState } from 'react'
import Son from './son'

function Father() {


  const [data, setData] = useState(0)

  const getSon = (msg) => {
    console.log(msg)
  }

  return (
    <div>
      <Son
      {/*定義一個方法用於接收子組件傳值*/}
      name = 'bob' d = {data} giveFather={(msg) => getSon(msg)}
      ></Son>
      <button onClick={() => setData(data + 1)}>+1</button>
    </div>
  )

}



export default Father


// 子組件
import { useState } from 'react'


function Son (props) {

  // 接收父組件方法 通過此方法傳值給父組件
  const set = () => {
    props.giveFather('兒子給父親的')
  }


  return (
    <div>
      <div>{props.name}</div>
      <div>{props.d}</div>
      <button onClick={set}>給父親</button>
    </div>
  )
}



export default Son

React.memo

一個高階組件,用於優化React組件的性能。它可以幫助我們避免不必要的渲染,從而提高應用程式的性能。當組件的props沒有改變時,React.memo會使用之前的渲染結果,而不會重新渲染組件。這對於那些渲染開銷較大的組件特別有用。

import React from 'react';

const MyComponent = React.memo(props => {
  // 組件代碼
}, (prevProps, currentProps) => {
  
  // prevProps 上次props
  // currentProps 當前props

  return Boolean;
  // false 渲染
  // true 不渲染
});

// 在上面的代碼中,我們將一個函數組件傳遞給React.memo(),並將其返回的新組件賦值給MyComponent。現在,MyComponent將只在其props發生更改時重新渲染。

// 需要註意的是,React.memo()僅檢查props的淺層比較。如果props包含複雜的對象或函數,可能需要手動實現更深層次的比較。
import React, { useState } from "react";

// 子組件
const SonMemo = React.memo(
  // 第一個參數 接收一個hook
  (props) => {
    return (
      <div>{props.data}</div>
    )
    // 第二個參數 接收一個函數
  }, (prevProps, currentProps) => {
    // 偶數不渲染
    // 奇數渲染
    return currentProps.data % 2 === 0
  }
)


function FatherMemo () {

  const [num, setNum] = useState(0)

  return (
    <div>
      <h1>{num}</h1>
      {/*點擊加一*/}
      <button onClick={() => setNum(num + 1)}>按鈕</button>
      <SonMemo data={num}></SonMemo>
    </div>
  )

}


export default FatherMemo;

React hooks中的過期閉包問題

什麼是閉包

過期閉包概念

過期閉包(stale closure)是指一個閉包在創建之後,所引用的外部作用域內的變數已經被修改,但閉包內仍然保存了舊值。這就導致閉包中的代碼與外部作用域內的實際狀態不一致,從而造成錯誤的結果。

useEffect中過期閉包體現和解決

// react hook中useEffect的過期閉包
import { useEffect, useState } from "react"


function ExpiredClosure () {

  const [num, setNum] = useState(0)

  useEffect(
    () => {
      setInterval(() => {
        // 這裡的num在初始化useEffect執行時取到0之後 因為閉包num值不會自動更新
        console.log(num)
      }, 2000)
    }, []
  )

return (
  <div>
    <h1>{num}</h1>
    <button onClick={() => setNum(num + 1)}>+1</button>
  </div>
)

}


export default ExpiredClosure


// 解決react hook中useEffect過期閉包問題
import { useEffect, useState } from "react"


function ExpiredClosure () {

  const [num, setNum] = useState(0)

  useEffect(
    () => {
      const timer = setInterval(() => {
        console.log(num)
      }, 2000)
      return () => {
        // 當組件卸載時 清除計時器
        clearInterval(timer)
      }
      // 添加num為依賴項
    }, [num]
  )

return (
  <div>
    <h1>{num}</h1>
    <button onClick={() => setNum(num + 1)}>+1</button>
  </div>
)

}


export default ExpiredClosure

useState中過期閉包體現和解決

// react hook中useState的過期閉包
import { useState } from "react";


function ExpiredClosure2 () {

  const [num, setNum] = useState(0)


  // 點擊正常+1
  const add = () => {
    setNum(num + 1)
  }
  
  // 假設點擊時num為3 兩秒+2 = 5 在兩秒之間不管點擊多少次+1操作num變為678910...最後num都為5
  const add2 = () => {
    setTimeout(() => {
      setNum(num + 2)
    }, 2000)
  }

  // 當我們點擊+2時候會取得當前值 之後點擊其他改變num值 +2中的num都不會隨之改變 兩秒後取得的num+2給setNum後 渲染頁面

  return (
    <div>
      <h1>{num}</h1>
      <button onClick={add}>+1</button><br />
      <button onClick={add2}>+2</button>
    </div>
  )

}


export default ExpiredClosure2;


// 解決react hook中useState過期閉包問題
import { useState } from "react";


function ExpiredClosure2 () {

  const [num, setNum] = useState(0)



  const add = () => {
    setNum(num + 1)
  }

  const add2 = () => {
    setTimeout(() => {
      // setNum中可以傳入一個函數 這個函數接收一個參數 用於獲取當前num值
      setNum((currentNum) => currentNum + 2)
    }, 2000)
  }

  return (
    <div>
      <h1>{num}</h1>
      <button onClick={add}>+1</button><br />
      <button onClick={add2}>+2</button>
    </div>
  )

}


export default ExpiredClosure2;


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 雖然已經有很多詩詞類的資料庫,最近又再次找了一下古詩詞類的數據,又發現了一些,可是真的是各有各的優點,各有各的特色,之後不再重找詩詞類的數據了。 今天這個詩詞鑒賞數據也不錯,有分類TAG,也有譯文、註釋、品析、朝代,但是又有些不足,詳見下麵說明: 朝代記錄統計:金朝(15)、近代(8)、兩漢(143 ...
  • 這是從一個中藥大全查詢系統中破解提取出來的中藥驗方大全,整理出了數以萬計的各家經方、時方、驗方以及秘方的用藥方劑組成,用法用量以及每組方劑的功效性能、主治應用等。有了這樣一套完善的醫學資料你可以節省很多查閱資料的時間可以更方便快捷的查閱你需要的信息。 加味涼血退斑湯 組成:鮮生地30克,鮮蘆根30克 ...
  • 中國出海中東和北非地區的策略類手游《蘇丹的復仇》(Revenge of Sultans,ROS)和華為HMS生態深度合作,為本地用戶帶來創新游戲體驗,成為當地廣受歡迎的游戲之一,下載量居應用市場前列。2023年5月10日,在阿聯酋迪拜舉辦的HUAWEI P60系列及旗艦產品發佈會中,ONEMT中東G ...
  • 本文主要介紹在業務複雜化背景下,京東零售購物車團隊努力踐行工匠精神,通過全非同步化改造提升系統性能、提升用戶體驗。通過本文,讀者可以瞭解購物車中台進行全非同步化改造的總體方案,以及方案落地過程中遇到的問題及解決方法,讀者可重點關註文中提到的多分頁並行後,分頁精細控制及底層RPC異常信息問題。 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 avaScript中有些API可能使用率比較低,下麵我們逐一介紹它們的用法和使用場景。 至於標題,主要是想讓你進來看看,兄弟們別打我! Blob API Blob API 用於處理二進位數據,可以方便地將數據轉換為Blob對象或從Blob ...
  • ## n 如果在我的電腦上已經安裝了nodejs,但是覺得這個版本不好用,或者是不相容公司的項目,那麼可以使用n進行node的版本管理。n相對於nvm來說,安裝起來還是非常方便的。 ## 安裝 #### 1. 首先確定nodejs版本,確定已安裝nodejs ``` node -v ``` #### ...
  • Deferred Components,官方實現的Flutter代碼動態下發的方案。本文主要介紹官方方案的實現細節,探索在國內環境下使用Deferred Components,並且實現了最小驗證demo。讀罷本文,你就可以實現Dart文件級別代碼的動態下發。 ...
  • 在 JavaScript 中, undefined 和 null 是兩個特殊的值,用於表示缺失或空值。 undefined 是一個表示未定義或未賦值的原始值。它在以下情況下使用: 1. 變數聲明瞭但未初始化時,預設為 undefined 。 let x; console.log(x); // und ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...