Bagaimana cara mendeklarasikan variabel global di React?

106

Saya menginisialisasi i18nobjek terjemahan sekali dalam sebuah komponen (komponen pertama yang dimuat dalam aplikasi). Objek yang sama diperlukan di semua komponen lainnya. Saya tidak ingin menginisialisasi ulang di setiap komponen. Bagaimana jalannya? Membuatnya tersedia untuk lingkup jendela tidak membantu karena saya perlu menggunakannya dalam render()metode.

Harap sarankan solusi umum untuk masalah ini dan bukan solusi khusus i18n.

sapy
sumber
1
Anda dapat menggunakan Reduxatau Fluxpustaka yang dapat menangani data atau status secara global. dan Anda dapat melewatinya dengan mudah melalui semua komponen Anda
vistajess
Ada cara lain? Kami memulai proyek tanpa Kerangka Kerja React karena itu adalah hari-hari awal React. Sekarang menghubungkan setiap komponen ke toko Redux akan membutuhkan usaha besar.
sapy
3
Apakah sesuatu seperti react-global berhasil untuk Anda?
TwoStraws

Jawaban:

50

Mengapa Anda tidak mencoba menggunakan Konteks ?

Anda dapat mendeklarasikan variabel konteks global di salah satu komponen induk dan variabel ini akan dapat diakses di seluruh pohon komponen dengan this.context.varname. Anda hanya perlu menentukan childContextTypesdan getChildContextdalam komponen induk dan setelah itu Anda dapat menggunakan / memodifikasi ini dari komponen manapun dengan hanya menentukan contextTypesdi komponen anak.

Namun, harap perhatikan ini seperti yang disebutkan dalam dokumen:

Sama seperti variabel global sebaiknya dihindari saat menulis kode yang jelas, Anda harus menghindari penggunaan konteks dalam banyak kasus. Secara khusus, pikirkan dua kali sebelum menggunakannya untuk "menyimpan pengetikan" dan menggunakannya alih-alih meneruskan alat peraga eksplisit.

Naisheel Verdhan
sumber
30
Menutup . tetapi Semua komponen tidak memiliki hubungan anak induk, dan Konteks tidak bekerja di luar pohon itu. Saya ingin i18n di seluruh Aplikasi.
sapy
@sapy inilah mengapa Anda harus menggunakan i18n sebagai status redux bukan sebagai variabel konteks lihat jawaban saya di sini: stackoverflow.com/questions/33413880/…
Fareed Alnamrouti
9
Jawaban yang mengerikan.
r3wt
Dari sisi saya, saya akan merekomendasikan menggunakan redux sebagai gantinya, dan khusus untuk Aplikasi besar
Hosny Ben
37

Beyond React

Anda mungkin tidak menyadari bahwa impor sudah bersifat global . Jika Anda mengekspor objek (tunggal), objek tersebut dapat diakses secara global sebagai pernyataan impor dan juga dapat dimodifikasi secara global .

Jika Anda ingin menginisialisasi sesuatu secara global tetapi memastikannya hanya dimodifikasi sekali, Anda dapat menggunakan pendekatan tunggal ini yang awalnya memiliki properti yang dapat dimodifikasi tetapi kemudian Anda dapat menggunakannya Object.freezesetelah penggunaan pertama untuk memastikannya tidak dapat diubah dalam skenario init Anda.

const myInitObject = {}
export default myInitObject

lalu dalam metode init Anda mereferensikannya:

import myInitObject from './myInitObject'
myInitObject.someProp = 'i am about to get cold'
Object.freeze(myInitObject)

Surat myInitObjectwasiat masih bersifat global karena dapat dirujuk di mana saja sebagai impor tetapi akan tetap dibekukan dan dibuang jika ada yang mencoba untuk memodifikasinya.

Jika menggunakan react-create-app

(Apa yang saya cari sebenarnya) Dalam skenario ini Anda juga dapat menginisialisasi objek global dengan rapi saat mereferensikan variabel lingkungan.

Membuat file .env di root proyek Anda dengan REACT_APP_variabel awalan di dalamnya cukup berhasil. Anda dapat mereferensikan dalam JS dan JSX process.env.REACT_APP_SOME_VARsesuai kebutuhan DAN tidak dapat diubah menurut desain.

Ini menghindari harus mengatur window.myVar = %REACT_APP_MY_VAR%dalam HTML.

Lihat detail yang lebih berguna tentang ini dari Facebook secara langsung:

https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables

Jason Sebring
sumber
6
Sejujurnya ini adalah tip yang bagus, saya mengalami masalah dengan token autentikasi saya karena saya menggunakan Server Side Rendering. Saya akhirnya memuat dari penyimpanan lokal pada pemuatan pertama dan kemudian menyimpannya ke dalam file Config terpisah yang bisa saya impor. Jawaban yang bagus.
Delapan
1
Ini adalah jawaban terbaik sejauh ini!
thiloilg
33

Tidak disarankan tetapi .... Anda dapat menggunakan componentWillMount dari kelas aplikasi Anda untuk menambahkan variabel global Anda melaluinya ... mirip seperti ini:

componentWillMount: function () {
    window.MyVars = {
        ajax: require('../helpers/ajax.jsx'),
        utils: require('../helpers/utils.jsx')
    };
}

masih menganggap ini hack ... tetapi itu akan menyelesaikan pekerjaan Anda

btw componentWillMount dijalankan satu kali sebelum rendering, lihat selengkapnya di sini: https://reactjs.org/docs/react-component.html#mounting-componentwillmount

rokyed
sumber
1
Ini adalah peretasan untuk kasus penggunaan tertentu. Saya mengintegrasikan aplikasi React ke dalam konteks aplikasi non-React lain di perusahaan saya. Ini sepertinya cara yang bagus untuk mengungkap metode publik untuk aplikasi konsumsi. Apakah aku salah? Apakah ada cara yang lebih baik?
mccambridge
2
Perhatikan juga bahwa componentWillMounttidak digunakan lagi: reactjs.org/blog/2018/03/27/update-on-async-rendering.html
RyanNerd
@mccambridge Saya tahu ini terlambat tetapi saya akan mengirim fungsi dari aplikasi non-React ke React yang akan Anda panggil untuk mengirim info. Btw, Anda dapat melakukan ini dengan iframe.
Nic Szerman
6

Buat file bernama "config.js" di folder ./src dengan konten ini:

module.exports = global.config = {
    i18n: {
        welcome: {
            en: "Welcome",
            fa: "خوش آمدید"
        }
        // rest of your translation object
    }
    // other global config variables you wish
};

Di file utama Anda "index.js" letakkan baris ini:

import './config';

Di mana pun Anda membutuhkan objek, gunakan ini:

global.config.i18n.welcome.en
Alireza
sumber
5

Dapat menyimpan variabel global di webpack yaitu di webpack.config.js

externals: {
  'config': JSON.stringify(GLOBAL_VARIABLE: "global var value")
}

Dalam modul js bisa dibaca seperti

var config = require('config')
var GLOBAL_VARIABLE = config.GLOBAL_VARIABLE

Semoga ini bisa membantu.

Shashank Bhong
sumber
4

Cara terbaik yang saya temukan sejauh ini adalah dengan menggunakan React Context tetapi mengisolasinya di dalam komponen penyedia tingkat tinggi .

Nick Tsoyrektsidis
sumber
2

Anda dapat menggunakan mixin dalam bereaksi https://facebook.github.io/react/docs/reusable-components.html#mixins .

Ramratan Gupta
sumber
7
Catatan: Jika Anda menggunakan Sintaks ES6 (yang sekarang direkomendasikan) atau komponen murni, mixin tidak tersedia. Direkomendasikan untuk membuat komponen Anda. medium.com/@dan_abramov/…
Aren
1
Ini sepertinya ide yang bagus karena Anda dapat memusatkan logika Anda dan kemudian pindah ke Flux jenis penyimpanan lain (misalnya Penyimpanan Lokal atau sisi klien DB)
dcsan
2
Jawaban ini seharusnya diperluas untuk menyertakan contoh kode. Tautan bisa rusak.
vapcguy
0

Ini adalah pendekatan modern, menggunakan globalThis, kami mengambil untuk aplikasi React Native kami .

globalThis sekarang termasuk dalam ...


appGlobals.ts

// define our parent property accessible via globalThis. Also apply the TypeScript type.
var app: globalAppVariables;

// define the child properties and their types. 
type globalAppVariables = {
  messageLimit: number;
  // more can go here. 
};

// set the values.
globalThis.app = {
  messageLimit: 10,
  // more can go here.
};


// Freeze so these can only be defined in this file.
Object.freeze(globalThis.app);


App.tsx ( file titik masuk utama kami )

import './appGlobals'

// other code


anyWhereElseInTheApp.tsx

const chatGroupQuery = useQuery(GET_CHAT_GROUP_WITH_MESSAGES_BY_ID, {
  variables: {
    chatGroupId,
    currentUserId: me.id,
    messageLimit: globalThis.app.messageLimit, // 👈 used here.
  },
});
GollyJer
sumber
-6

Saya tidak tahu apa yang mereka coba katakan dengan hal-hal "Konteks Bereaksi" - mereka berbicara bahasa Yunani, bagi saya, tapi begini cara saya melakukannya:

Membawa nilai antar fungsi, di halaman yang sama

Dalam konstruktor Anda, ikat penyetel Anda:

this.setSomeVariable = this.setSomeVariable.bind(this);

Kemudian nyatakan fungsi tepat di bawah konstruktor Anda:

setSomeVariable(propertyTextToAdd) {
    this.setState({
        myProperty: propertyTextToAdd
    });
}

Saat Anda ingin menyetelnya, panggil this.setSomeVariable("some value");

(Anda bahkan mungkin bisa lolos dengan this.state.myProperty = "some value";)

Jika Anda ingin mendapatkannya, telepon var myProp = this.state.myProperty;

Menggunakan alert(myProp);seharusnya memberi Anda some value.

Metode perancah ekstra untuk membawa nilai di seluruh halaman / komponen

Anda dapat menetapkan model ke this(secara teknis this.stores), sehingga Anda dapat mereferensikannya dengan this.state:

import Reflux from 'reflux'
import Actions from '~/actions/actions`

class YourForm extends Reflux.Store
{
    constructor()
    {
        super();
        this.state = {
            someGlobalVariable: '',
        };
        this.listenables = Actions;
        this.baseState = {
            someGlobalVariable: '',
        };
    }

    onUpdateFields(name, value) {
        this.setState({
            [name]: value,
        });
    }

    onResetFields() {
        this.setState({
           someGlobalVariable: '',
        });
    }
}
const reqformdata = new YourForm

export default reqformdata

Simpan ini ke folder bernama storessebagai yourForm.jsx.

Kemudian Anda dapat melakukan ini di halaman lain:

import React from 'react'
import Reflux from 'reflux'
import {Form} from 'reactstrap'
import YourForm from '~/stores/yourForm.jsx'

Reflux.defineReact(React)

class SomePage extends Reflux.Component {
    constructor(props) {
        super(props);
        this.state = {
            someLocalVariable: '',
        }
        this.stores = [
            YourForm,
        ]
    }
    render() {

        const myVar = this.state.someGlobalVariable;
        return (
            <Form>
                <div>{myVar}</div>
            </Form>
        )
    }
}
export default SomePage

Jika Anda telah mengatur this.state.someGlobalVariablekomponen lain menggunakan fungsi seperti:

setSomeVariable(propertyTextToAdd) {
    this.setState({
       myGlobalVariable: propertyTextToAdd
   });
}

yang Anda ikat dalam konstruktor dengan:

this.setSomeVariable = this.setSomeVariable.bind(this);

nilai dalam propertyTextToAddakan ditampilkan dengan SomePagemenggunakan kode yang ditunjukkan di atas.

vapcguy
sumber
3
Maaf karena saya baru di sini, tetapi saya baru saja belajar React dan tidak yakin mengapa jawaban ini mendapatkan begitu banyak
suara negatif
3
@someoneuseless Persis! Dan itulah mengapa saya menolak untuk menghapusnya dan bersujud kepada massa. Hanya karena mereka ingin menggunakan "Konteks" (apapun itu) dan objek lucu lainnya tidak berarti semua orang perlu. High Five!
vapcguy