React: Mencegah rendering dengan React.memo dan useContext hook.

Dibuat pada 19 Mar 2019  ·  37Komentar  ·  Sumber: facebook/react

Apakah Anda ingin meminta fitur atau melaporkan bug ?

serangga

Apa perilaku saat ini?

Saya tidak dapat mengandalkan data dari API konteks dengan menggunakan (kait useContext) untuk mencegah perenderan ulang yang tidak perlu dengan React.memo

Jika perilaku saat ini adalah bug, berikan langkah-langkah untuk mereproduksi dan jika mungkin demo minimal dari masalah tersebut. Rekatkan tautan ke contoh JSFiddle (https://jsfiddle.net/Luktwrdm/) atau CodeSandbox (https://codesandbox.io/s/new) Anda di bawah ini:

React.memo(() => {
const [globalState] = useContext(SomeContext);

render ...

}, (prevProps, nextProps) => {

// How to rely on context in here?
// I need to rerender component only if globalState contains nextProps.value

});

Apa perilaku yang diharapkan?

Saya seharusnya memiliki akses ke konteks dalam panggilan balik argumen kedua React.memo untuk mencegah rendering
Atau saya harus memiliki kemungkinan untuk mengembalikan instance lama dari komponen reaksi di badan fungsi.

Versi React yang mana, dan browser/OS mana yang terpengaruh oleh masalah ini?
16.8.4

Komentar yang paling membantu

Ini berfungsi seperti yang dirancang. Ada diskusi yang lebih panjang tentang ini di https://github.com/facebook/react/issues/14110 jika Anda penasaran.

Katakanlah untuk beberapa alasan Anda memiliki AppContext yang nilainya memiliki properti theme , dan Anda hanya ingin merender ulang beberapa ExpensiveTree pada appContextValue.theme perubahan.

TLDR adalah untuk saat ini, Anda memiliki tiga opsi:

Opsi 1 (Diutamakan): Pisahkan konteks yang tidak berubah bersama

Jika kita hanya membutuhkan appContextValue.theme dalam banyak komponen tetapi appContextValue itu sendiri terlalu sering berubah, kita dapat memisahkan ThemeContext dari AppContext .

function Button() {
  let theme = useContext(ThemeContext);
  // The rest of your rendering logic
  return <ExpensiveTree className={theme} />;
}

Sekarang setiap perubahan AppContext tidak akan merender ulang konsumen ThemeContext .

Ini adalah perbaikan yang disukai. Maka Anda tidak memerlukan dana talangan khusus.

Opsi 2: Bagi komponen Anda menjadi dua, masukkan memo di antaranya

Jika karena alasan tertentu Anda tidak dapat membagi konteks, Anda masih dapat mengoptimalkan rendering dengan membagi komponen menjadi dua, dan meneruskan props yang lebih spesifik ke bagian dalam. Anda masih akan membuat yang terluar, tetapi harus murah karena tidak melakukan apa-apa.

function Button() {
  let appContextValue = useContext(AppContext);
  let theme = appContextValue.theme; // Your "selector"
  return <ThemedButton theme={theme} />
}

const ThemedButton = memo(({ theme }) => {
  // The rest of your rendering logic
  return <ExpensiveTree className={theme} />;
});

Opsi 3: Satu komponen dengan useMemo di dalamnya

Terakhir, kita dapat membuat kode kita sedikit lebih bertele-tele tetapi menyimpannya dalam satu komponen dengan membungkus nilai kembalian dalam useMemo dan menentukan dependensinya. Komponen kita masih akan mengeksekusi ulang, tetapi React tidak akan merender ulang pohon anak jika semua input useMemo adalah sama.

function Button() {
  let appContextValue = useContext(AppContext);
  let theme = appContextValue.theme; // Your "selector"

  return useMemo(() => {
    // The rest of your rendering logic
    return <ExpensiveTree className={theme} />;
  }, [theme])
}

Mungkin ada lebih banyak solusi di masa depan tetapi inilah yang kami miliki sekarang.

Namun, perhatikan bahwa opsi 1 lebih disukai — jika beberapa konteks terlalu sering berubah, pertimbangkan untuk memisahkannya .

Semua 37 komentar

Ini berfungsi seperti yang dirancang. Ada diskusi yang lebih panjang tentang ini di https://github.com/facebook/react/issues/14110 jika Anda penasaran.

Katakanlah untuk beberapa alasan Anda memiliki AppContext yang nilainya memiliki properti theme , dan Anda hanya ingin merender ulang beberapa ExpensiveTree pada appContextValue.theme perubahan.

TLDR adalah untuk saat ini, Anda memiliki tiga opsi:

Opsi 1 (Diutamakan): Pisahkan konteks yang tidak berubah bersama

Jika kita hanya membutuhkan appContextValue.theme dalam banyak komponen tetapi appContextValue itu sendiri terlalu sering berubah, kita dapat memisahkan ThemeContext dari AppContext .

function Button() {
  let theme = useContext(ThemeContext);
  // The rest of your rendering logic
  return <ExpensiveTree className={theme} />;
}

Sekarang setiap perubahan AppContext tidak akan merender ulang konsumen ThemeContext .

Ini adalah perbaikan yang disukai. Maka Anda tidak memerlukan dana talangan khusus.

Opsi 2: Bagi komponen Anda menjadi dua, masukkan memo di antaranya

Jika karena alasan tertentu Anda tidak dapat membagi konteks, Anda masih dapat mengoptimalkan rendering dengan membagi komponen menjadi dua, dan meneruskan props yang lebih spesifik ke bagian dalam. Anda masih akan membuat yang terluar, tetapi harus murah karena tidak melakukan apa-apa.

function Button() {
  let appContextValue = useContext(AppContext);
  let theme = appContextValue.theme; // Your "selector"
  return <ThemedButton theme={theme} />
}

const ThemedButton = memo(({ theme }) => {
  // The rest of your rendering logic
  return <ExpensiveTree className={theme} />;
});

Opsi 3: Satu komponen dengan useMemo di dalamnya

Terakhir, kita dapat membuat kode kita sedikit lebih bertele-tele tetapi menyimpannya dalam satu komponen dengan membungkus nilai kembalian dalam useMemo dan menentukan dependensinya. Komponen kita masih akan mengeksekusi ulang, tetapi React tidak akan merender ulang pohon anak jika semua input useMemo adalah sama.

function Button() {
  let appContextValue = useContext(AppContext);
  let theme = appContextValue.theme; // Your "selector"

  return useMemo(() => {
    // The rest of your rendering logic
    return <ExpensiveTree className={theme} />;
  }, [theme])
}

Mungkin ada lebih banyak solusi di masa depan tetapi inilah yang kami miliki sekarang.

Namun, perhatikan bahwa opsi 1 lebih disukai — jika beberapa konteks terlalu sering berubah, pertimbangkan untuk memisahkannya .

Kedua opsi ini akan menyelamatkan dari rendering anak-anak jika tema tidak berubah.

@gaearon Apakah Tombol anak-anak atau apakah Tombol membuat anak-anak? Saya kehilangan beberapa konteks bagaimana ini digunakan.

Menggunakan unstable_Profiler opsi 2 masih akan memicu onRender callback tetapi tidak memanggil logika render yang sebenarnya. Mungkin aku melakukan sesuatu yang salah? ~ https://codesandbox.io/s/kxz4o2oyoo~ https://codesandbox.io/s/00yn9yqzjw

Saya memperbarui contoh agar lebih jelas.

Menggunakan opsi stable_Profiler 2 masih akan memicu callback onRender tetapi tidak memanggil logika render yang sebenarnya. Mungkin aku melakukan sesuatu yang salah? https://codesandbox.io/s/kxz4o2oyoo

Itulah inti dari opsi itu. :-)

Mungkin solusi yang baik untuk itu adalah memiliki kemungkinan "mengambil" konteks dan merender komponen hanya jika diberikan callback return true misalnya:
useContext(ThemeContext, (contextData => contextData.someArray.length !== 0 ));

Masalah utama dengan kait yang benar-benar saya temui adalah bahwa kita tidak dapat mengelola dari dalam kait apa yang dikembalikan oleh komponen - untuk mencegah rendering, mengembalikan nilai memo, dll.

Jika kita bisa, itu tidak akan bisa dikomposisi.

https://overreacted.io/why-isnt-xa-hook/#not -a-hook-usebailout

Opsi 4: Jangan gunakan konteks untuk propagasi data tetapi berlangganan data. Gunakan useSubscription (karena sulit untuk menulis untuk mencakup semua kasus).

Ada cara lain untuk menghindari rendering ulang.
"Anda perlu memindahkan BEJ naik satu tingkat dari komponen rendering ulang maka itu tidak akan dibuat ulang setiap kali"

Info lebih lanjut disini

Mungkin solusi yang baik untuk itu adalah memiliki kemungkinan "mengambil" konteks dan merender komponen hanya jika diberikan callback return true misalnya:
useContext(ThemeContext, (contextData => contextData.someArray.length !== 0 ));

Masalah utama dengan kait yang benar-benar saya temui adalah bahwa kita tidak dapat mengelola dari dalam kait apa yang dikembalikan oleh komponen - untuk mencegah rendering, mengembalikan nilai memo, dll.

Alih-alih benar/salah di sini... dapatkah kami menyediakan fungsi berbasis identitas yang memungkinkan kami untuk mengelompokkan data dari konteks?

const contextDataINeed = useContext(ContextObj, (state) => state['keyICareAbout'])

di mana useContext tidak akan muncul di komponen ini kecuali hasil dari pemilih fn adalah identitas yang berbeda dari hasil sebelumnya dari fungsi yang sama.

menemukan perpustakaan ini yang mungkin menjadi solusi bagi Facebook untuk berintegrasi dengan kait https://blog.axlight.com/posts/super-performant-global-state-with-react-context-and-hooks/

Ada cara lain untuk menghindari rendering ulang.
"Anda perlu memindahkan BEJ naik satu tingkat dari komponen rendering ulang maka itu tidak akan dibuat ulang setiap kali"

Info lebih lanjut disini

Masalahnya adalah mungkin mahal untuk merestrukturisasi pohon komponen hanya untuk mencegah rendering ulang dari atas ke bawah.

@fuleinist Pada akhirnya, ini tidak jauh berbeda dari MobX, meskipun banyak disederhanakan untuk kasus penggunaan tertentu. MobX sudah berfungsi seperti itu (juga menggunakan Proksi), statusnya bermutasi dan komponen yang menggunakan bit status tertentu dirender ulang, tidak ada yang lain.

@gaearon Saya tidak tahu apakah saya melewatkan sesuatu, tetapi saya telah mencoba opsi kedua dan ketiga Anda dan mereka tidak berfungsi dengan benar. Tidak yakin apakah ini hanya bug ekstensi chrome yang bereaksi atau ada tangkapan lain. Berikut adalah contoh formulir sederhana saya, di mana saya melihat rendering kedua input. Di konsol saya melihat memo itu melakukan tugasnya tetapi DOM dirender ulang setiap saat. Saya telah mencoba 1000 item dan acara onChange sangat lambat, itu sebabnya saya pikir memo() tidak berfungsi dengan konteks dengan benar. Terima kasih atas saran apa pun:

Berikut adalah demo dengan 1000 item/kotak teks. Namun dalam demo itu alat dev tidak menunjukkan re-render. Anda harus mengunduh sumber di lokal untuk mengujinya: https://codesandbox.io/embed/zen-firefly-d5bxk

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

const FormContext = createContext();

const FormProvider = ({ initialValues, children }) => {
  const [values, setValues] = useState(initialValues);

  const value = {
    values,
    setValues
  };

  return <FormContext.Provider value={value}>{children}</FormContext.Provider>;
};

const TextField = memo(
  ({ name, value, setValues }) => {
    console.log(name);
    return (
      <input
        type="text"
        value={value}
        onChange={e => {
          e.persist();
          setValues(prev => ({
            ...prev,
            [name]: e.target.value
          }));
        }}
      />
    );
  },
  (prev, next) => prev.value === next.value
);

const Field = ({ name }) => {
  const { values, setValues } = useContext(FormContext);

  const value = values[name];

  return <TextField name={name} value={value} setValues={setValues} />;
};

const App = () => (
  <FormProvider initialValues={{ firstName: "Marr", lastName: "Keri" }}>
    First name: <Field name="firstName" />
    <br />
    Last name: <Field name="lastName" />
  </FormProvider>
);

export default App;

image

Di sisi lain pendekatan ini tanpa konteks berfungsi dengan benar, masih dalam debug ini lebih lambat dari yang saya harapkan tetapi setidaknya rerender tidak apa-apa

import React, { useState, memo } from "react";
import ReactDOM from "react-dom";

const arr = [...Array(1000).keys()];

const TextField = memo(
  ({ index, value, onChange }) => (
    <input
      type="text"
      value={value}
      onChange={e => {
        console.log(index);
        onChange(index, e.target.value);
      }}
    />
  ),
  (prev, next) => prev.value === next.value
);

const App = () => {
  const [state, setState] = useState(arr.map(x => ({ name: x })));

  const onChange = (index, value) =>
    setState(prev => {
      return prev.map((item, i) => {
        if (i === index) return { name: value };

        return item;
      });
    });

  return state.map((item, i) => (
    <div key={i}>
      <TextField index={i} value={item.name} onChange={onChange} />
    </div>
  ));
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

image

@marrkeri Saya tidak melihat sesuatu yang salah di cuplikan kode pertama. Komponen yang disorot dalam alat dev adalah Field yang menggunakan konteks, bukan TextField yang merupakan komponen memo dan mengimplementasikan fungsi areEqual.

Saya pikir masalah kinerja dalam contoh kode dan kotak berasal dari 1000 komponen yang menggunakan konteks. Faktorkan ulang ke satu komponen yang menggunakan konteks, katakan Fields , dan kembalikan dari komponen itu (dengan peta) TextField untuk setiap nilai.

@marrkeri Saya tidak melihat sesuatu yang salah di cuplikan kode pertama. Komponen yang disorot dalam alat dev adalah Field yang menggunakan konteks, bukan TextField yang merupakan komponen memo dan mengimplementasikan fungsi areEqual.

Saya pikir masalah kinerja dalam contoh kode dan kotak berasal dari 1000 komponen yang menggunakan konteks. Faktorkan ulang ke satu komponen yang menggunakan konteks, katakan Fields , dan kembalikan dari komponen itu (dengan peta) TextField untuk setiap nilai.

Seperti yang Anda katakan saya berada di bawah pemikiran yang sama bahwa harus dirender ulang setiap saat tapi ( ) hanya jika nilainya diubah. Tapi itu mungkin hanya masalah alat dev karena saya telah menambahkan padding di sekitar dan sebagai gantinya dirender. Cek gambar ini
image

image

Saya belum menangkap poin kedua Anda tentang refactoring ke satu komponen . Bisakah Anda melakukan snapshot? Dan apa pendapat kalian tentang jumlah maksimum yang ditampilkan yang ok tanpa lagging? Apakah 1000 terlalu banyak?

@marrkeri Saya menyarankan sesuatu seperti ini: https://codesandbox.io/s/little-night-p985y.

Apakah ini alasan mengapa react-redux harus berhenti menggunakan manfaat API konteks stabil dan meneruskan status saat ini ke konteks saat mereka bermigrasi ke Hooks?

Jadi sepertinya ada

Opsi 4: berikan fungsi berlangganan sebagai nilai konteks, seperti di era konteks lama

Ini mungkin satu-satunya pilihan jika Anda tidak mengontrol penggunaan (diperlukan untuk opsi 2-3) dan tidak dapat menghitung semua pemilih yang mungkin (diperlukan untuk opsi 1), tetapi masih ingin mengekspos Hooks API

const MyContext = createContext()
export const Provider = ({children}) => (
  <MyContext.provider value={{subscribe: listener => ..., getValue: () => ...}}>
    {children}
  </MyContext.provider>
)

export const useSelector = (selector, equalityFunction = (a, b) => a === b) => {
  const {subscribe, getValue} = useContext(MyContext)
  const [value, setValue] = useState(getValue())
  useEffect(() => subscribe(state => {
      const newValue = selector(state)
      if (!equalityFunction(newValue, value) {
        setValue(newValue)
      }
  }), [selector, equalityFunction])
}

@Hypnosphi : kami berhenti meneruskan status toko dalam konteks (implementasi v6) dan beralih kembali ke langganan toko langsung (implementasi v7) karena kombinasi masalah kinerja dan ketidakmampuan untuk menyelamatkan pembaruan yang disebabkan oleh konteks (yang membuatnya tidak mungkin membuat React-Redux hooks API berdasarkan pendekatan v6).

Untuk lebih jelasnya, lihat posting saya Sejarah dan Implementasi React-Redux .

Saya membaca utasnya tetapi saya masih bertanya-tanya - apakah satu-satunya opsi yang tersedia saat ini untuk merender secara kondisional pada perubahan konteks, "Opsi 1 2 3 4" yang tercantum di atas? Apakah ada hal lain yang sedang dikerjakan untuk secara resmi mengatasi ini atau apakah "4 solusi" dianggap cukup dapat diterima?

Saya menulis di utas lain, tetapi untuk berjaga-jaga. Inilah solusi _unofficial_.
proposal useContextSelector dan perpustakaan use-context-selector di userland.

sejujurnya, ini membuat saya berpikir bahwa kerangka kerja belum siap untuk sepenuhnya menjalankan fungsi dan kaitan seperti yang sedang kita dorong. Dengan kelas dan metode siklus hidup Anda memiliki cara yang rapi untuk mengendalikan hal-hal ini dan sekarang dengan kait itu adalah sintaks yang jauh lebih buruk dan kurang dapat dibaca

Opsi 3 sepertinya tidak berfungsi. Apakah saya melakukan sesuatu yang salah? https://stackblitz.com/edit/react-w8gr8z

@Martin , saya tidak setuju dengan itu.

Pola kait dapat dibaca dengan dokumentasi dan kode yang terorganisir dengan baik
struktur dan kelas React dan siklus hidup semuanya dapat diganti dengan fungsional
yang setara.

Sayangnya, pola reaktif tidak dapat dicapai dengan Bereaksi bersama melalui
baik kelas Bereaksi atau kait.

Pada Sabtu, 11 Januari 2020 pukul 09:44 Martin Genev [email protected]
menulis:

sejujurnya, ini membuat saya berpikir bahwa kerangka kerja belum siap untuk digunakan
sepenuhnya ke dalam fungsi dan kait seperti kita sedang didorong. Dengan kelas
dan metode siklus hidup Anda memiliki cara yang rapi untuk mengendalikan hal-hal ini dan
sekarang dengan kait itu adalah sintaks yang jauh lebih buruk dan kurang dapat dibaca


Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub
https://github.com/facebook/react/issues/15156?email_source=notifications&email_token=AAI4DWUJ7WUXMHAR6F2KVXTQ5D25TA5CNFSM4G7UEEO2YY3PNVWWK3TUL52HS4DFVREXG43VMVBWW63LN5MVXHJKTUL1
atau berhenti berlangganan
https://github.com/notifications/unsubscribe-auth/AAI4DWUCO7ORHV5OSDCE35TQ5D25TANCNFSM4G7UEEOQ
.

@mgenev Opsi 3 mencegah <ExpensiveTree /> , nama berbicara sendiri)

@Hypnosphi terima kasih, itu benar.
https://stackblitz.com/edit/react-ycfyye

Saya menulis ulang dan sekarang komponen rendering (tampilan) yang sebenarnya tidak dirender ulang, tetapi semua wadah (konteks terhubung) melakukan render pada setiap perubahan prop pada konteks, tidak peduli apakah itu digunakan di dalamnya. Sekarang satu-satunya pilihan yang bisa saya lihat adalah mulai membagi konteks, tetapi beberapa hal benar-benar global dan membungkus pada tingkat tertinggi dan perubahan pada penyangga apa pun di dalamnya akan menyebabkan semua wadah menyala di seluruh aplikasi, saya tidak' tidak mengerti bagaimana itu bisa baik untuk kinerja ...

Apakah ada contoh yang baik tentang bagaimana melakukan ini dengan cara yang performan? Dokumen resmi sangat terbatas

Anda dapat mencoba opsi saya 4, yang pada dasarnya adalah apa yang dilakukan react-redux secara internal
https://github.com/facebook/react/issues/15156#issuecomment -546703046

Untuk mengimplementasikan fungsi subscribe , Anda dapat menggunakan sesuatu seperti Observables atau EventEmitter, atau cukup tulis sendiri logika langganan dasar:

function StateProvider({children}) {
  const [state, dispatch] = useReducer(reducer, initialState)
  const listeners = useRef([])
  const subscribe = listener => {
    listeners.current.push(listener)
  }
  useEffect(() => {
    listeners.current.forEach(listener => listener(state)
  }, [state])

  return (
    <DispatchContext.Provider value={dispatch}>
      <SubscribeContext.Provider value={{subscribe, getValue: () => state}}>
          {children}      
      </SubscribeContext.Provider>
    </DispatchContext.Provider>
  );
}

Bagi yang berminat, berikut perbandingan berbagai perpustakaan yang agak terkait dengan topik ini.
https://github.com/dai-shi/will-this-react-global-state-work-in-concurrent-mode

Upaya terbaru saya adalah memeriksa dukungan percabangan status dengan useTransition yang akan menjadi penting dalam Mode Bersamaan yang akan datang.
Pada dasarnya, jika kita menggunakan status dan konteks React secara normal, tidak apa-apa. (jika tidak, kita perlu trik, misalnya, ini .)

Terima kasih @dai-shi Saya sangat menyukai paket Anda dan saya ingin mengadopsinya.

@dai-shi hai, saya baru saja menemukan lib react-tracked dan itu terlihat sangat bagus jika menyelesaikan masalah kinerja dengan konteks seperti yang dijanjikan. Apakah masih aktual atau lebih baik menggunakan yang lain? Di sini saya melihat contoh yang baik dari penggunaannya juga menampilkan cara membuat level middleware dengan use-reducer-async https://github.com/dai-shi/react-tracked/blob/master/examples/12_async/src/store .ts Terima kasih untuk itu. Saat ini saya telah melakukan sesuatu yang serupa menggunakan useReducer , membungkus dispatch dengan milik saya sendiri untuk middleware async dan menggunakan Context tetapi mengkhawatirkan masalah kinerja rendering di masa mendatang karena pembungkusan konteks.

@bobrosoft react-tracked cukup stabil, menurut saya (sebagai salah satu produk pengembang pasti). Umpan balik sangat diterima dan begitulah cara perpustakaan dapat ditingkatkan. Saat ini, secara internal menggunakan fitur React yang tidak terdokumentasi, dan saya harap kami dapat menggantinya dengan primitif yang lebih baik di masa depan. use-reducer-async hampir seperti gula sintaks sederhana yang tidak akan pernah salah.

HoC ini bekerja untuk saya:
````
import React, { useMemo, ReactElement, FC } dari 'react';
impor pengurangan dari 'lodash/kurangi';

ketik Selector = (konteks: any) => any;

antarmuka SelectorObject {
}

const denganKonteks = (
Komponen: FC,
Konteks: apa saja,
pemilih: SelectorObject,
): FC => {
kembali (alat peraga: apa saja): ReactElement => {
const Konsumen = ({ konteks }: apa saja): ReactElement => {
const contextProps = kurangi(
pemilih,
(acc: any, pemilih: Selector, kunci: string): any => {
nilai const = pemilih(konteks);
acc[kunci] = nilai;
kembalikan;
},
{},
);
kembali gunakanMemo(
(): ReactElement => ,
[...Object.values(props), ...Object.values(contextProps)],
);
};
kembali (

{(konteks: apa saja): ReactElement => }

);
};
};

ekspor default denganContext;
````

contoh penggunaan:

export default withContext(Component, Context, { value: (context): any => context.inputs.foo.value, status: (context): any => context.inputs.foo.status, });

ini bisa dilihat sebagai Konteks yang setara dengan redux mapStateToProps

Saya membuat hoc hampir sangat mirip dengan connect() di redux

const withContext = (
  context = createContext(),
  mapState,
  mapDispatchers
) => WrapperComponent => {
  function EnhancedComponent(props) {
    const targetContext = useContext(context);
    const { ...statePointers } = mapState(targetContext);
    const { ...dispatchPointers } = mapDispatchers(targetContext);
    return useMemo(
      () => (
        <WrapperComponent {...props} {...statePointers} {...dispatchPointers} />
      ),
      [
        ...Object.values(statePointers),
        ...Object.values(props),
        ...Object.values(dispatchPointers)
      ]
    );
  }
  return EnhancedComponent;
};

Penerapan :

const mapActions = state => {
  return {};
};

const mapState = state => {
  return {
    theme: (state && state.theme) || ""
  };
};
export default connectContext(ThemeContext, mapState, mapActions)(Button);


Pembaruan: Pada akhirnya, saya beralih ke EventEmitter untuk perubahan cepat, data granular dengan pendengar dinamis (saat mouse bergerak). Saya menyadari bahwa saya adalah alat yang lebih baik untuk pekerjaan itu. Konteks sangat bagus untuk berbagi data secara umum, tetapi tidak pada kecepatan refresh yang tinggi.

Bukankah itu berarti berlangganan secara deklaratif atau tidak berlangganan konteks? Membungkus komponen secara kondisional di komponen lain yang menggunakan useContext().

Persyaratan utama adalah bahwa komponen dalam tidak dapat memiliki status, karena secara efektif akan menjadi instance yang berbeda karena percabangan. Atau, mungkin Anda dapat melakukan pra-render komponen kemudian menggunakan cloneElement untuk memperbarui props.

Beberapa komponen tidak ada hubungannya dengan konteks di rendernya tetapi perlu "hanya membaca nilai" darinya. Apa yang saya lewatkan?
context

Apakah Context._currentValue aman digunakan dalam produksi?

Saya mencoba berlangganan komponen ke konteks yang semurah mungkin untuk dirender. Tapi kemudian saya mendapati diri saya melewati alat peraga seperti dengan cara lama dengan kode sphagetti atau menggunakan memo untuk menghindari berlangganan pembaruan ketika tidak ada yang logis dengan pembaruan. Solusi memo bagus ketika komponen Anda dirender bergantung pada konteks tetapi sebaliknya ...

@vamshi9666 apakah Anda sering menggunakannya? apakah Anda dapat melihat pro/kontra pendekatan Anda? Saya sangat menyukainya. Saya suka kesamaan dengan redux tetapi juga bagaimana hal itu membebaskan Anda untuk menulis manajemen status aplikasi dan logika secara bebas sebagai konteks

Saya menemukan https://recoiljs.org/ solusi yang baik untuk masalah ini. Saya pikir akan luar biasa jika Anda mengintegrasikannya ke dalam React.

@vamshi9666 apakah Anda sering menggunakannya? apakah Anda dapat melihat pro/kontra pendekatan Anda? Saya sangat menyukainya. Saya suka kesamaan dengan redux tetapi juga bagaimana hal itu membebaskan Anda untuk menulis manajemen status aplikasi dan logika secara bebas sebagai konteks

Saya menggunakannya hanya di satu tempat dan tujuan awal saya adalah mengisolasi manajemen negara dari jsx tetapi juga tidak membuat not boilerplate. jadi ketika saya memperluas fungsi mutasi, itu terlihat sangat mirip dengan peredam redux dan pola pembuat tindakan. Yang bahkan lebih baik. tapi saya tidak melihat titik untuk menemukan kembali sesuatu, padahal sebenarnya sudah ada.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat