React-Hooks verwenden State und andere React-Features, ohne eine Klasse zu schreiben

Haken

Eins, Haken

1.useState()

​ 1) State Hook ermöglicht es Funktionskomponenten, auch einen Zustandszustand zu haben und Lese- und Schreiboperationen an Zustandsdaten durchzuführen

​ 2). Syntax const [Frucht, setFruit] = useState(123)

3. useState() Beschreibung:

​ Parameter: Der bei der ersten Initialisierung angegebene Wert wird intern zwischengespeichert

Rückgabewert: ein Array mit 2 Elementen (xxx, setxxx), das erste ist der interne aktuelle Statuswert und das zweite ist die Funktion zum Aktualisieren des Statuswerts

  	var ageState = useState(123); // 返回一个有两个元素的数组
  	var age = ageState[0]; // 数组里的第一个值
  	var setAge = ageState[1]; // 数组里的第二个值

​ 4) Die Schreibmethode in setState() 2

​ setState(newValue): Der Parameter ist kein Funktionswert, geben Sie den neuen Zustandswert direkt an und verwenden Sie ihn intern, um den ursprünglichen Zustandswert zu überschreiben

​ setState(val => newVal): Der Parameter ist eine Funktion, die den ursprünglichen Statuswert empfängt und den neuen Statuswert zurückgibt, der intern verwendet wird, um den ursprünglichen Statuswert zu überschreiben

// 一个组件中可以声明多个 state 变量!
  const [xxx, setxxx] = useState(1);
  const [xxxx, setxxxx] = useState('222');
  const [xxxxx, setxxxxx] = useState([{
    
    name:'zhangning'}]);

2.useEffect()

​ 1. Effekt-Hook ermöglicht es Ihnen, Seiteneffekte in Funktionskomponenten auszuführen (wird verwendet, um Lebenszyklus-Hooks in Klassenkomponenten zu simulieren).

Standardmäßig wird es nach dem ersten Rendern und nach jeder Aktualisierung ausgeführt

React garantiert, dass das DOM jedes Mal aktualisiert wurde, wenn der Effekt ausgeführt wird.

2) Nebenwirkungen in React:

Senden Sie eine Ajax-Anforderungsdatenerfassung, stellen Sie den Abonnement-/Starttimer ein, ändern Sie das reale DOM manuell

​ 3) Der Effekt wird nach jeder Rendering-Runde ausgeführt, aber Sie können festlegen, dass er nur ausgeführt wird, wenn sich einige Änderungen ergeben.

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

	useEffect(()=>{
    
    }, [xxx])

	useEffect(()=>{
    
    
        // effect 可选的清楚机制(订阅或计时器ID等),为防止内存泄漏,清楚函数会在组件卸载前执行
        return ()=>{
    
    }
    }, [xxx])

3.useLayoutEffect()

1. Genauso wie useEffect, wird es effect synchron nach allen DOM-Änderungen aufrufen

2. Es kann verwendet werden, um das DOM-Layout zu lesen und das erneute Rendern synchron auszulösen. Der Aktualisierungsplan in useLayoutEffect wird synchron aktualisiert, bevor der Browser zeichnet

4. Benutzerdefinierter Haken

​ 1) Ein benutzerdefinierter Hook ist eine Funktion, die mit use beginnen muss, und andere Hooks können innerhalb der Funktion aufgerufen werden

// 监听浏览器窗口大小
export function useWinSize() {
    
    
  const [size, setSize] = useState({
    
    
    width: document.documentElement.clientWidth,
    height: document.documentElement.clientHeight
  });

  const onResize = useCallback(() => {
    
    
    setSize({
    
    
      width: document.documentElement.clientWidth,
      height: document.documentElement.clientHeight
    });
  }, [size.width]);

  useEffect(() => {
    
    
    window.addEventListener('resize', onResize);
    // return 表示只有销毁的时候才执行
    return () => {
    
    
      window.removeEventListener('resize', onResize);
    };
  }, []);

  return size;
}
const width = useWinSize()

5.useRef()

​ 1).Ref Hook kann Tags oder andere Daten in der Komponente in der Funktionskomponente speichern und finden

2) Syntax: const refCont = useRef()

3) Funktion: Speichern Sie das Label-Objekt, die Funktion ist die gleiche wie React.CreateRef()

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

function Index() {
    
    
  const chRef = useRef();
  // 通过 current 访问子组件
  console.log(chRef.current)
  return (
    <>
      <Children ref={
    
    chRef}/>
    </>
  );
}
export default Index;

6.useImperativeHandle()

1. Sie können den Instanzwert anpassen, der für die übergeordnete Komponente verfügbar gemacht wird, wenn Sie ref verwenden.

useImperativeHandle(ref, createHandle, [deps])

2. Verwenden Sie mit forwardRef

// 父组件
function Parent() {
    
    
  const childRef = useRef();
  return (
    <div>
      <AllProjectTable ref={
    
    childRef}/>
      <button onClick={
    
    () => childRef.current.handleClick()}>aaaa</button>
    </div>
  );
}

// 子组件
const Child=(props, ref)=> {
    
    
    const [state, setState] = useSataeO();
  const handleClick = () => {
    
    };
  // 暴露给父组件的方法
  useImperativeHandle(ref, () => ({
    
    
    handleClick
  }));
  return (
    <>
      <button onClick={
    
    () => handleClick()}>dddd</button>
    </>
  );
}
// 子组件通过 forward 包裹起来
export default forwardRef(Child);

7.useContext()

Verstehen: Eine Kommunikationsmethode zwischen Komponenten, die oft für die Kommunikation zwischen Vorfahrkomponenten und Nachkommenkomponenten verwendet wird

1. Erhalte das Kontextobjekt und gebe den aktuellen Wert des Kontexts zurück.Der aktuelle Kontextwert wird durch den Eigenschaftswert prop des <MyContext.Provider>bestimmt, der der aktuellen Komponente in der oberen Komponente am nächsten liegt

2. Selbst wenn der Vorgänger React.memo oder shouldComponentUpdate verwendet, wird es erneut gerendert, wenn die Komponente selbst useContext verwendet.

3. Die Komponente, die useContext aufruft, wird immer neu gerendert, wenn sich der Kontextwert ändert

使用方式
1. 创建 Context 容器对象:
    const MyContext = React.createContext()
2.渲染子组件时,外面包裹 MyContext.Provider 通过 value 属性给后代组件传递数据
    <MyContext.Provider value={数据}>子组件</MyContext.Provider>
3.后代组件读取数据:
    // 第一种:仅适用于类组件,了解下就行
    const contextType = MyContext // 声明接收 context
    this.context // 读取 context 中的 value 数据
    // 第二种:函数组件、类组件都可以使用
    <MyContext.Consumer>
        {
            value => {// value 就是 context 中的 value 数据
                显示内容            
            }
        }
    </MyContext.Consumer>

Beispiel

import React, {createContext, useContext} from 'react';

// 创建 Context 容器对象
// 渲染子组件时,外面包裹 MyContext.Provider,通过 value 属性给后代组件传递数据
const MyContext = createContext({});
const {Provider, Consumer} = MyContext;

function AAA() {
  const name = 'zhangning';
  const age = 24;
  return (
    <div>
      我是祖组件,name:{name}
      <Provider value={
   
   {name, age}}>
        <BBB/>
      </Provider>
    </div>
  );
}
function BBB() {
  return <div><CCC/></div>;
}
function CCC() {
  // 这里也可以使用 useContext 直接获取数据,个人感觉更加方便实用
  // const {name} = useContext(MyContext);
  return <div>
    从祖组件获取的name:
    <Consumer>
      {value => {return `${value.name},年龄${value.age}`;}}
    </Consumer>
  </div>;
}

export default AAA;

8.useReducer()

1. Es ist äquivalent zu einer Alternative zu useState, die einen Reducer von (state, action)=>newState empfängt und den aktuellen Status und die passende Dispatch-Methode zurückgibt.

2. In einigen Szenarien ist useReducer besser anwendbar, z. B. wenn die Zustandslogik komplex ist und mehrere Unterwerte enthält oder der nächste Zustand vom vorherigen Zustand abhängt usw. Darüber hinaus kann die Verwendung von useReducer auch die Leistung von Komponenten optimieren, die tiefgreifende Aktualisierungen auslösen, und kann den Versand an Unterkomponenten anstelle von Callback-Funktionen übergeben

const initialState = {count: 0};

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

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

​ Die offizielle Website rät davon ab, Reduzierer zu verwenden, um Redux zu simulieren...

9.useMemo()

1. Geben Sie einen gespeicherten Cache-Wert zurück

Übergeben Sie die Erstellungsfunktion und das Abhängigkeitsarray als Parameter an useMemo, und der gespeicherte Cache-Wert wird nur dann neu berechnet, wenn sich die Abhängigkeiten ändern. Vermeiden Sie teure Berechnungen bei jedem Rendering.

Die an useMemo übergebene Funktion wird während des Renderns ausgeführt. Keine Abhängigkeiten, bei jedem Rendern werden neue Werte berechnet

​ UseMemo kann als Lösung zur Leistungsoptimierung verwendet werden.

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

10.useCallback()

1. Übergeben Sie die Callback-Funktion und das Abhängigkeitsarray als Parameter und geben Sie die gespeicherte zwischengespeicherte Version der Callback-Funktion zurück.Die Callback-Funktion wird nur aktualisiert, wenn sich die Abhängigkeiten ändern.

​ useCallback(fn, deps) ist äquivalent zu useMemo(()=>fu, deps)

Konzeptionell sollten alle Werte, auf die in Callback-Funktionen verwiesen wird, im Abhängigkeitsarray erscheinen.

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

2. Komponentenoptimierung

1.Komponente

Lassen Sie uns zunächst die Leistungsoptimierung von Klassenkomponenten in React verstehen, wobei wir uns hauptsächlich auf die folgenden zwei Punkte konzentrieren

1. Wenn setState aufgerufen wird, wird die Komponente erneut gerendert, unabhängig davon, ob sich der Status davor oder danach ändert

2. Wenn die übergeordnete Komponente aktualisiert wird, wird auch die untergeordnete Komponente automatisch aktualisiert (geringe Effizienz)

Möglichkeiten zur Effizienzsteigerung:

Lassen Sie die Komponente render() ausführen, wenn sich der Status oder die Requisitendaten ändern

Grund: Solange die Methode setState aufgerufen wird, gibt shouldComponentUpdate() in der Komponente immer true zurück, wodurch die Komponente gerendert wird

Lösung

// 方案一:通过重写 shouldComponentUpdate()方法,比较新旧 state 或 props,有变化返回 true,没有变化返回 false
shouldComponentUpdate(nextProps, nextState) {
  console.log(this.props, this.state);// 当前 props 和 state
  console.log(nextProps, nextState);// 改变之后的 props 和 state
  if (JSON.stringify(nextProps) === JSON.stringify(this.props)
    || JSON.stringify(nextState) === JSON.stringify(this.state)) {
    return false;
  } else {
    return true;
  }
}
// 方案二: 使用 PureComponent 
// PureComponent 重写了 sholdComponentUpdate(),只有 state 或 props 数据有变化才返回 true
// 注意:只是进行 state 和 props 数据的浅比较,如果只是数据对象内部数据变了,返回 false、
// 不要直接修改 state 数据,而是要产生新数据
// 项目中一般使用 pureComponent 来优化
// pureComponent 缺点:可能会因深层的数据不一致而产生错误的否定判断,从而shouldComponentUpdate 的结果返回 false,界面得不到更新

2. Optimierung des Leistungsschemas in Hooks

​ Das shouldComponentUpdate geht in der funktionalen Komponente verloren, und ich habe mich entschieden, es zu aktualisieren, indem ich den Status davor und danach beurteile. React unterscheidet in funktionalen Komponenten nicht mehr die beiden Zustände mount und update, was bedeutet, dass jeder Aufruf einer funktionalen Komponente alle ihre internen Sketches ausführt, was zu einem großen Performance-Verlust führt. Hier erscheinen zwei Hooks, useMemo und useCallback, in Hooks, um die Performance-Lösung funktionaler Komponenten zu lösen.

Schauen Sie sich zuerst den Quellcode von useMemo und useCallback an

function useCallback<T extends (...args: any[]) => any>(callback: T, deps: DependencyList): T;

function useMemo<T>(factory: () => T, deps: DependencyList | undefined): T;

​ Die Parameterform ist konsistent mit useEffect, und useEffect wird verwendet, um Nebenwirkungen zu behandeln, aber diese beiden nicht.

Sowohl useMemo als auch useCallback werden ausgeführt, wenn die Komponente zum ersten Mal gerendert wird, und werden erneut ausgeführt, wenn sich die Abhängigkeit ändert;

Beide geben den zwischengespeicherten Wert zurück, useMemo gibt die zwischengespeicherte Variable zurück und useCallback gibt die zwischengespeicherte Funktion zurück.

Vorteile: Die von useMemo umschlossene Variable entspricht dem Zwischenspeichern der Variablen.Wenn die übergeordnete Komponente erneut gerendert wird, ändert sich die Variable nicht ==> die Unterkomponente wird nicht erneut gerendert

// useMemo 示例
function Test() {
  const [count, setCount] = useState(1);
  const [val, setVal] = useState('');

  // sum1 每次在 count 与 val 有一个改变的时候都会刷新组件重新执行 sum1。
  // 但是这里的计算 sum1 只依赖于 count 的值,在 val 修改的时候没有必要进行 sum1 的计算。
  // 这种情况下,我们就可以使用 useMemo,只在count 的值修改时执行计算(sum2)
  const sum1 = () => {
    console.log('sum1111');
    let sum = 0;
    for (let i = 0; i < count; i++) {
      sum += i;
    }
    return sum;
  };

  // 每次在 count 的值改变的时候才重新执行计算
  const sum2 = useMemo(() => {
    console.log('sum2222');
    let sum = 0;
    for (let i = 0; i < count; i++) {
      sum += i;
    }
    return sum;
  }, [count]);

  return (
    <div>
      <h1>{count}+++{val}+++{sum1()}+++{sum2()}</h1>
      <div>
        <button onClick={() => setCount(count + 1)}>+++</button>
        <input type='text' value={val} onChange={event => setVal(event.target.value)}/>
      </div>
    </div>
  );
}

Rückruf verwenden

​ Warum useCallback verwenden und die Leistungsverbesserung, die useCallback bringen kann

​Ähnlich wie useMemo ist es sehr nützlich, wenn die Callback-Funktion optimierten untergeordneten Komponenten gegeben wird, die Referenzgleichheit verwenden, um unnötiges Rendern zu vermeiden, und hat den gleichen Effekt wie pureComponent. Das heißt, wenn die übergeordnete Komponente eine Funktion an die untergeordnete Komponente übergibt, wird sich die an die untergeordnete Komponente übergebene Funktionsreferenz ändern, da die Aktualisierung der übergeordneten Komponente bewirkt, dass die Funktion neu generiert wird, was die untergeordnete Komponente dazu veranlasst In vielen Fällen ist die Aktualisierung der untergeordneten Komponente nicht erforderlich, daher wird useCallback verwendet, um die an die untergeordnete Komponente übergebene Funktion zwischenzuspeichern.

Vorteile: Die von useCallback umschlossene Funktion entspricht dem Caching der Funktion.Wenn die übergeordnete Komponente erneut gerendert wird, wird die Funktion nicht neu definiert ==> die untergeordnete Komponente wird nicht erneut gerendert

const Child = ({getNum}) => {
  return <h1>数据:{getNum}</h1>;
};

function Test() {
  const [count, setCount] = useState(1);
  const [val, setVal] = useState('');

  const sum = useCallback(() => {
    return Array.from({length: count}, (v, i) => i).reduce((a, b) => a + b);
  }, [count]);

  return (
    <div>
      <Child getNum={sum}/>
      <h1>{count}+++{val}++++{sum()}</h1>
      <div>
        <button onClick={() => setCount(count + 1)}>+++</button>
        <input type='text' value={val} onChange={event => setVal(event.target.value)}/>
      </div>
    </div>
  );
}
// 以上只有当 count 改变的时候child组件才会重新渲染

Zusammenfassen:

memo wird verwendet, um Unterkomponenten zu umschließen

​ Ob das Rendern von Memos für eine Komponente wiederholt wird

	<Header />

usememo Ob wiederholt für einen Teil der Funktionslogik ausgeführt werden soll

	()=>{}

useEffect wird nach dem Rendern durchgeführt

useMemo wird während des Renderns ausgeführt (leere Arrays werden nur einmal ausgeführt)

	useMemo(()=>{},[])

Verwenden Sie Rückruf

	useMemo(()=>{fn})等价于useCallback(fn)

3.Memo

memo() ähnelt PureComponent, es hilft uns zu kontrollieren, wann Komponenten neu gerendert werden sollen

Das Verständnis ist, dass Memo uns hilft, Komponenten zwischenzuspeichern und anhand der Bedingung des zweiten Parameters zu beurteilen, ob wir erneut rendern sollen

Beispiel:

1. Memo ist nicht anwendbar, wenn die übergeordnete Komponente aktualisiert wird, wird auch die untergeordnete Komponente aktualisiert

​ 2. Wenn die übergeordnete Komponente aktualisiert wird, gilt das Unterkomponenten-Memo nicht für den zweiten Parameter. Standardmäßig wird jedes Element in pre und next verglichen. Die übergeordnete Komponente übergibt keine Attribute an die untergeordnete Komponente. Die übergeordnete Komponente wird aktualisiert die Attribute und die untergeordnete Komponente wird nicht aktualisiert

import React, {memo} from 'react';
import './index.scss';

const Header = memo(props => {
  return (
    <div>
      header 组件
    </div>
  );
});

export default Header;

3. Verwenden Sie den zweiten Parameter von memo, um alle Attribute zu vergleichen, die von der übergeordneten Komponente an die untergeordnete Komponente übergeben wurden, und aktualisieren Sie sie, falls es Änderungen gibt

import React, {memo} from 'react';
import './index.scss';

const Header = memo(props => {
  return (
    <div>
      header 组件
    </div>
  );
}, (pre, next) => {
  const keys = Reflect.ownKeys(next);
  return keys.every(i => pre[i] === next[i]);
});

export default Header;

​ 4. Verwenden Sie den zweiten Parameter von memo, um ein bestimmtes Attribut zu vergleichen und alle Attribute zu vergleichen, die von der übergeordneten Komponente an die untergeordnete Komponente übergeben wurden, und zu aktualisieren, wenn es eine Änderung gibt

import React, {memo} from 'react';
import './index.scss';

const Header = memo(props => {
  return (
    <div>
      header 组件
    </div>
  );
}, (pre, next) => {
  return pre.val === next.val;
});

export default Header;

drei,

Wie übergibt man dynamisch eine Struktur (Label) mit Inhalt wie innerhalb einer Komponente?

​ In Vue: Verwenden Sie die Slot-Technologie, d. h. führen Sie die Struktur durch den Körper des Komponenten-Tags

In Reaktion:

Verwenden Sie untergeordnete Requisiten: Übergeben Sie die Struktur durch den Hauptteil des Komponenten-Tags, Beispiel 1 unten

Verwenden Sie Render-Props: Übergeben Sie die Struktur über das Attribut des Komponenten-Tags, verwenden Sie im Allgemeinen das Attribut der Render-Funktion, das folgende Beispiel 2

Verwenden Sie die Kinderrequisiten

// children props 示例1
import React from 'react';

function AAA() {
  return (
    <><BBB>hello!</BBB></>
  );
}

function BBB(props) {
  return <>
    <h2>我是BBB组件</h2>
    {/*这里可以打印 AAA 父组件传递过来的 hello!,通过 props.children 接收*/}
    {props.children}
  </>;
}

export default AAA;

Verwenden Sie Render-Requisiten

    // A 和 B 组件父子组件
    <A render={(data)=><B data={data}></B>}></A>
    A 组件:{this.props.render(内部 state 数据)}
    B 组件:读取 A 组件传入的数据显示 {this.props.data}
// 示例2
import React from 'react';

function AAA() {
  return (
    <>
      <BBB render={(name) => <CCC name={name}/>}></BBB>
      {/*<BBB peiqi={(name) => <CCC name={name}/>}></BBB>*/}
    </>
  );
}

function BBB(props) {
  const name = 'zhangning';
  return <>
    <h2>我是BBB组件</h2>
    {/*调用 render 方法,预留一个位子,放置组件,传递 name*/}
    {/*在 A 组件中,使用 B 组件,调用 render 方法,加载 B 组件的子组件 C,传递name,相当于 vue 中的插槽slot*/}
    {/*这里 render 可以写任意字符,在调用的时候保持一致就可,render 便于阅读*/}
    {/*{props.peiqi(name)}*/}{/*A 组件中使用的时候也要使用 peiqi*/}
    {props.render(name)}
  </>;
}

function CCC(props) {
  return <>
    <h2>我是BBB组件</h2>
    接收到B组件中的数据name:{props.name}
  </>;
}

export default AAA;

4. Komponentenkommunikationsverfahren

1. Beziehung zwischen Komponenten

1. Eltern-Kind-Komponenten

2. Brother-Komponenten (nicht verschachtelte Komponenten)

3. Großeltern- und Enkelkinder-Komponenten (ebenenübergreifende Komponenten)

几种通信方式:
    1.props:
    	children props
    	render props
    2.消息订阅-发布
    	pubs-sub、event 等等
    3.集中式管理:
    	redux、dva
    4.context
    	生产者-消费者模式
比较好的搭配方式:
    父子组件:props
    兄弟组件:消息订阅-发布、集中式管理
    祖孙组件:消息订阅-发布、集中式管理、context(开发用的少,封装插件用的多)

Guess you like

Origin blog.csdn.net/qq_37440870/article/details/126614055