จะประกาศตัวแปรส่วนกลางใน React ได้อย่างไร?


117

ฉันเริ่มต้นi18nออบเจ็กต์การแปลหนึ่งครั้งในองค์ประกอบ (ส่วนประกอบแรกที่โหลดในแอป) จำเป็นต้องใช้วัตถุเดียวกันในส่วนประกอบอื่น ๆ ทั้งหมด ฉันไม่ต้องการเริ่มต้นใหม่ในทุกองค์ประกอบ มีอะไรอยู่รอบ ๆ ? การทำให้พร้อมใช้งานสำหรับขอบเขตหน้าต่างไม่ได้ช่วยอะไรเพราะฉันต้องใช้มันrender()วิธีการ

โปรดแนะนำวิธีแก้ปัญหาทั่วไปสำหรับปัญหาเหล่านี้ไม่ใช่วิธีแก้ปัญหาเฉพาะของ i18n


1
คุณสามารถใช้ReduxหรือFluxไลบรารีที่สามารถจัดการข้อมูลหรือสถานะทั่วโลก และคุณสามารถส่งผ่านส่วนประกอบทั้งหมดของคุณได้อย่างง่ายดาย
ทิวทัศน์

วิธีอื่น ๆ ? เราเริ่มโครงการโดยไม่มี React Framework เนื่องจากเป็น React ในวันแรก ตอนนี้การเชื่อมต่อทุกส่วนประกอบกับ Redux store จะต้องใช้ความพยายามอย่างมาก
sapy

3
สิ่งที่ต้องการตอบสนองทั่วโลกสำหรับคุณหรือไม่?
TwoStraws

คำตอบ:


52

ทำไมคุณไม่ลองใช้บริบทล่ะ?

คุณสามารถประกาศตัวแปรบริบทของโลกในใด ๆ this.context.varnameของส่วนประกอบแม่และตัวแปรนี้จะสามารถเข้าถึงได้ทั่วต้นไม้องค์ประกอบโดย คุณต้องระบุchildContextTypesและgetChildContextในองค์ประกอบหลักเท่านั้นหลังจากนั้นคุณสามารถใช้ / แก้ไขสิ่งนี้จากองค์ประกอบใดก็ได้โดยระบุcontextTypesในองค์ประกอบลูก

อย่างไรก็ตามโปรดสังเกตสิ่งนี้ตามที่กล่าวไว้ในเอกสาร:

เช่นเดียวกับที่หลีกเลี่ยงตัวแปรส่วนกลางได้ดีที่สุดเมื่อเขียนโค้ดที่ชัดเจนคุณควรหลีกเลี่ยงการใช้บริบทในกรณีส่วนใหญ่ โดยเฉพาะอย่างยิ่งให้คิดสองครั้งก่อนที่จะใช้เพื่อ "บันทึกการพิมพ์" และใช้แทนการส่งผ่านอุปกรณ์ประกอบฉากที่โจ่งแจ้ง


32
ปิด . แต่คอมโพเนนต์ทั้งหมดไม่มีความสัมพันธ์ลูกของผู้ปกครองและบริบทจะไม่ทำงานนอกเหนือจากโครงสร้างนั้น ฉันต้องการ i18n ในแอปพลิเคชัน
sapy

@sapy นี่คือเหตุผลที่คุณควรใช้ i18n เป็นสถานะ redux ไม่ใช่เป็นตัวแปรบริบทดูคำตอบของฉันที่นี่: stackoverflow.com/questions/33413880/…
Fareed Alnamrouti

10
คำตอบที่น่ากลัว
r3wt

จากด้านข้างของฉันฉันขอแนะนำให้ใช้ redux แทนและโดยเฉพาะอย่างยิ่งสำหรับแอพขนาดใหญ่
Hosny Ben

41

เกินกว่าจะตอบสนอง

คุณอาจไม่ทราบว่านำเข้าเป็น บริษัท ระดับโลกแล้ว ถ้าคุณส่งออกวัตถุ (เดี่ยว) เป็นแล้วทั่วโลกสามารถเข้าถึงได้เป็นคำสั่งนำเข้าและก็ยังสามารถแก้ไขได้ทั่วโลก

หากคุณต้องการเริ่มต้นบางสิ่งบางอย่างทั่วโลก แต่ตรวจสอบให้แน่ใจว่ามีการแก้ไขเพียงครั้งเดียวคุณสามารถใช้วิธีการแบบซิงเกิลตันซึ่งในตอนแรกมีคุณสมบัติที่ปรับเปลี่ยนได้ แต่คุณสามารถใช้Object.freezeหลังจากใช้ครั้งแรกเพื่อให้แน่ใจว่าไม่เปลี่ยนรูปในสถานการณ์เริ่มต้นของคุณ

const myInitObject = {}
export default myInitObject

จากนั้นในวิธีการเริ่มต้นของคุณอ้างถึง:

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

myInitObjectจะยังคงอยู่ทั่วโลกในขณะที่มันสามารถอ้างอิงได้ทุกที่เป็นการนำเข้าแต่จะยังคงแช่แข็งและโยนความพยายามถ้าทุกคนที่จะแก้ไขได้

หากใช้ react-create-app

(สิ่งที่ฉันกำลังมองหาจริงๆ) ในสถานการณ์นี้คุณยังสามารถเริ่มต้นอ็อบเจ็กต์ส่วนกลางทั้งหมดเมื่ออ้างอิงตัวแปรสภาพแวดล้อม

การสร้างไฟล์. envที่รูทของโปรเจ็กต์ของคุณโดยมีREACT_APP_ตัวแปรนำหน้าอยู่ภายในทำได้ดี คุณสามารถอ้างอิงภายใน JS และ JSX ได้process.env.REACT_APP_SOME_VARตามต้องการและไม่เปลี่ยนรูปตามการออกแบบ

วิธีนี้หลีกเลี่ยงการตั้งค่าwindow.myVar = %REACT_APP_MY_VAR%ใน HTML

ดูรายละเอียดที่เป็นประโยชน์เพิ่มเติมจาก Facebook โดยตรง:

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


7
นี่เป็นเคล็ดลับที่ยอดเยี่ยมจริงๆฉันมีปัญหากับโทเค็นการตรวจสอบสิทธิ์เนื่องจากฉันใช้การแสดงผลฝั่งเซิร์ฟเวอร์ ฉันโหลดจาก localstorage ในการโหลดครั้งแรกจากนั้นจัดเก็บลงในไฟล์ Config แยกต่างหากที่ฉันสามารถนำเข้าได้ คำตอบที่ดี
8

2
นี่คือคำตอบที่ดีที่สุด!
thiloilg

1
เพื่อนนี่เปิดตาของฉันมากกว่าที่ควร ... ขอบคุณจากนี้ฉันคิดว่าฉันจะดีขึ้น 20% FE dev: P
Outside_Box

34

ไม่แนะนำ แต่ .... คุณสามารถใช้ componentWillMount จากคลาสแอปของคุณเพื่อเพิ่มตัวแปรส่วนกลางของคุณ ... คล้าย ๆ กัน:

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

ยังคงคิดว่านี่เป็นการแฮ็ก ... แต่จะทำให้งานของคุณลุล่วง

btw componentWillMount ดำเนินการหนึ่งครั้งก่อนการแสดงผลดูเพิ่มเติมที่นี่: https://reactjs.org/docs/react-component.html#mounting-componentwillmount


1
เป็นการแฮ็กสำหรับกรณีการใช้งานบางอย่าง ฉันกำลังรวมแอป React เข้ากับบริบทของแอปอื่นที่ไม่ใช่ React ใน บริษัท ของฉัน นี่เป็นวิธีที่ดีในการเปิดเผยวิธีการสาธารณะสำหรับแอปที่ใช้งานอยู่ ฉันผิดเหรอ? มีวิธีที่ดีกว่า?
mccambridge

2
โปรดทราบว่าcomponentWillMountกำลังเลิกใช้งาน: reactjs.org/blog/2018/03/27/update-on-async-rendering.html
RyanNerd

@mccambridge ฉันรู้ว่ามันช้าไป แต่ฉันจะส่งฟังก์ชั่นจากแอพที่ไม่ตอบสนองไปยัง React ที่คุณจะโทรไปส่งข้อมูล Btw คุณสามารถทำได้ด้วย iframe
Nic Szerman

9

สร้างไฟล์ชื่อ "config.js" ในโฟลเดอร์. / src ด้วยเนื้อหานี้:

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

ในไฟล์หลัก "index.js" ให้ใส่บรรทัดนี้:

import './config';

ทุกที่ที่คุณต้องการวัตถุของคุณใช้สิ่งนี้:

global.config.i18n.welcome.en

5

สามารถเก็บตัวแปรส่วนกลางไว้ใน webpack เช่นใน webpack.config.js

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

ในโมดูล js สามารถอ่านเช่น

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

หวังว่านี่จะช่วยได้



2

คุณสามารถใช้ mixins ในการตอบสนองhttps://facebook.github.io/react/docs/reusable-components.html#mixins


7
หมายเหตุ: หากคุณใช้ ES6 Syntax (ซึ่งตอนนี้ขอแนะนำใหม่) หรือส่วนประกอบที่แท้จริงจะไม่มีส่วนผสม คำแนะนำคือการเขียนส่วนประกอบของคุณ medium.com/@dan_abramov/...
Aren

1
ดูเหมือนว่าจะเป็นความคิดที่ดีเมื่อคุณสามารถรวมตรรกะของคุณไว้ที่ส่วนกลางแล้วย้ายไปยังที่เก็บข้อมูลประเภทอื่น ๆ ของ Flux (เช่น Localstorage หรือ DB ฝั่งไคลเอ็นต์)
dcsan

2
คำตอบนี้ควรได้รับการขยายเพื่อรวมตัวอย่างโค้ด ลิงก์สามารถทำลายได้
vapcguy


1

นี่คือแนวทางที่ทันสมัยglobalThisซึ่งเราใช้สำหรับแอปReact Nativeของเรา

globalThis รวมอยู่ใน ...


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 ( ไฟล์จุดเข้าหลักของเรา )

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.
  },
});

-6

ฉันไม่รู้ว่าพวกเขาพยายามจะพูดอะไรกับเนื้อหา "React Context" - พวกเขากำลังพูดภาษากรีกกับฉัน แต่นี่คือวิธีที่ฉันทำ:

แบกรับค่าระหว่างฟังก์ชันในหน้าเดียวกัน

ในตัวสร้างของคุณผูกตัวตั้งค่าของคุณ:

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

จากนั้นประกาศฟังก์ชันด้านล่างตัวสร้างของคุณ:

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

เมื่อต้องการตั้งค่าโทร this.setSomeVariable("some value");

(คุณอาจจะหนีไปได้ this.state.myProperty = "some value"; )

อยากได้เมื่อไหร่โทร var myProp = this.state.myProperty;

การใช้ควรให้alert(myProp);some value

วิธีการนั่งร้านเสริมเพื่อนำค่าไปทั่วหน้า / ส่วนประกอบ

คุณสามารถกำหนดแบบจำลองให้กับthis(ในทางเทคนิคthis.stores) ดังนั้นคุณจึงสามารถอ้างอิงได้ด้วย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

บันทึกลงในโฟลเดอร์ชื่อstoresasyourForm.jsx .

จากนั้นคุณสามารถทำได้ในหน้าอื่น:

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

หากคุณตั้งค่าthis.state.someGlobalVariableในส่วนประกอบอื่นโดยใช้ฟังก์ชันเช่น:

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

ที่คุณผูกในตัวสร้างด้วย:

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

ค่าในpropertyTextToAddจะแสดงSomePageโดยใช้รหัสที่แสดงด้านบน


3
ขออภัยที่ยังใหม่ที่นี่ แต่ฉันเพิ่งเรียนรู้ React และไม่แน่ใจว่าทำไมคำตอบนี้ถึงได้รับการ
โหวตลดลง

3
@someoneuseless เป๊ะ! และนั่นคือเหตุผลที่ฉันปฏิเสธที่จะลบมันและให้ความสนใจกับคนจำนวนมาก เพียงเพราะพวกเขาต้องการใช้ "บริบท" (ไม่ว่าจะเป็นอะไรก็ตาม) และวัตถุตลกอื่น ๆ เหล่านี้ไม่ได้หมายความว่าทุกคนต้องทำ แตะมือ!
vapcguy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.