Как использовать глобальную переменную в нескольких файлах

Я пытался использовать глобальную переменную в приложении React для целей отладки и столкнулся с некоторыми проблемами, которые заставили меня понять, что я не понимаю, как работают глобальные переменные в javascript.

глобальный.js:

export let myGlobal = 0

IncButton.js:

import { Component } from 'react'
import { myGlobal } from './global'

class IncButton extends Component {
    render() {
        return (
            <button onClick = {() => { myGlobal = myGlobal + 1 }}>increase</button>
        )
    }
}

export default IncButton

window.inc = () => {
    myGlobal = myGlobal + 1
}

App.js:

import { myGlobal } from './global'
import IncButton from './IncButton'

function App() {
  return (
    <>
      {myGlobal}
      <IncButton />
    </>
  );
}
export default App;

Нажатие IncButton вызывает ReferenceError: assignment to undeclared variable myGlobal. Вызов inc() непосредственно из консоли вызывает ту же ошибку.

Использование let myGlobal = 0 в верхней части IncButton.js и удаление импорта устраняет ошибки, но, конечно, это приводит к тому, что App.js не видит тот же самый myGlobal. Я думаю, что импортированные переменные и переменные вне какой-либо функции или {} должны быть в одной области видимости.

Поэтому я хотел бы знать: почему вышеизложенное не работает, как правильно разделить глобальную переменную между файлами, и добавляет ли React какие-либо дополнительные сложности к этому?

Примечание 1. Остальной код для приведенного выше примера — это просто код по умолчанию из create-react-app.

Примечание 2: я знаю, что использование глобальных переменных часто не очень хорошая идея.

как правильно разделить глобальную переменную между файлами <-- Это невозможно сделать. Для этого вам нужно сохранить значение на сервере, обычно в базе данных. Хотя вы можете совместно использовать библиотеку JavaScript в файлах, все значения сбрасываются при загрузке каждой страницы, которая ее использует.

Scott Marcus 09.12.2020 19:37

Но поскольку модули es используют живые привязки, как объяснено в этом ответе, и поскольку несколько файлов могут импортировать один и тот же модуль, не должны ли в результате быть переменные, совместно используемые в файлах?

snowape 09.12.2020 19:40
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
2 753
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Требуется довольно много пояснений, чтобы объяснить, что происходит в вашем коде, но я постараюсь быть кратким.

Иметь это по-твоему

глобальный.js

На самом деле это не глобальный, а модуль, и экспортированные элементы доступны только для чтения.

Вы можете заставить его работать, экспортируя объект:

export let myGlobal = { count: 0 };

И изменив обработчик onClick на

() => { myGlobal.count++ }

Но ваши компоненты не будут перерисовываться, поскольку они не являются частью состояния, и поэтому React не заметит изменения.

Путь реакции

Если вы хотите разделить состояние между компонентами - вы должны либо поднять состояние, либо использовать контекстный API, как описано в этом ответе

Изменение на myGlobal = { count: 0 } предотвращает появление ошибок. Но доступ к myGlobal.count в App.js всегда показывает ноль, даже при нажатии кнопки для увеличения значения. Похоже, теперь есть 2 версии myGlobal.

snowape 09.12.2020 19:54

Как указано в ответе - App.js не будет повторно отображаться, потому что myGlobal не является частью состояния. Вы можете видеть, что значение разделяется, если вы принудительно выполняете повторную визуализацию App.js.

Daniel 09.12.2020 20:02

В необработанном проекте javascript вы можете экспортировать глобальную переменную в файл и импортировать в любое место в других файлах. Это то, что вы сделали.

Но в React, если вы хотите использовать глобальное состояние, вы должны использовать контекстный API. Ваш код не запускается, потому что myGlobal не объявлен как состояние. Таким образом, React не может отслеживать его состояние.

Правильный метод такой:

const {useState, useContext} = React;

// you can create context outside of React component
const CounterContext = React.createContext(0);
// export default CounterContext;


// import CounterContext from 'global/counter-context';
const ChildComponent = () => {

   const counter = useContext(CounterContext);
   
   return (
     <div className = "other-component">
     <p>This is Child Component that consumes CounterContext value </p>
     <p>Current counter is: {counter}</p>
     </div>
   );

};

// import CounterContext from 'global/counter-context';
const App = () => {
  const [counter, setCounter] = useState(0);
  return (
      <div className = "app">
      <CounterContext.Provider value = {counter}>
         <p>This is Context Provider component. Global state is maintained here and you can consume the state value in any other child components</p>
         <label>Click this button to increment global counter state: </label>
         <button onClick = {() => setCounter((oldCounter) => (oldCounter + 1))}>
           Increment
         </button>
         <ChildComponent />
      </CounterContext.Provider>
      </div>
    );
};

class Root extends React.Component {
  render() {
    return (<App />);
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
.app {
  border: 1px solid red;
  padding: 5px;
  margin: 5px;
}

button {
  margin-bottom: 5px;
  margin-left: 5px;
}

.other-component {
  border: 1px solid blue;
  padding: 5px;
  margin: 5px;
}
<script src = "https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src = "https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<div id = "root">
</div>

Справочник API хуков

Другие вопросы по теме