Проблема с файлом .env и приложением create-react-app - возвращает неопределенный - PullRequest
0 голосов
/ 05 августа 2020

Я знаю, что этот вопрос задавали бесчисленное количество раз, и поверьте мне, когда я скажу, что прочитал страницы здесь, на Stack Overflow, а также на других веб-сайтах, и, очевидно, просмотрел документацию. Либо я чего-то не понимаю, либо чего-то глупого, чего мне не хватает.

Я создал приложение React (используя npx create-response-app), чтобы создать небольшую службу информации о погоде с помощью API и API выборки (думаете, это так называется?). Это все фронтенд (я еще не начал изучать какие-либо бэкенды).

Моя проблема - мой файл .env. Как уже говорилось, я провел много исследований и поэтому могу (надеюсь) исключить следующее:

  1. Мой текстовый файл переменных окружения называется '.env' и расположен в моей папке root (т.е. в том же месте, что и папки package. json и sr c & publi c).

  2. В текстовом файле .env , переменная имеет префикс 'REACT_APP _'.

  3. Я почти уверен, что весь синтаксис и имена переменных верны, но это все еще может быть?

Когда я помещаю свой ключ API прямо в свою выборку, все работает отлично, но всегда не определено при попытке получить ключ API из файла .env. Я знаю, поскольку я занимаюсь только интерфейсом, а API все еще технически виден, если я нажимаю / загружаю на GitHub (или что-то еще), это не имеет значения, даже используя .gitignore, но я все равно хочу либо исправьте это, либо выясните, почему это не работает для моего собственного спокойствия.

Как я понимаю, с create-react-app никакие другие модули / зависимости (не уверен, что правильный термин) не нужны для установки через терминал, так как proccess.env сейчас включен. Насколько мне известно, proccess.env должен работать вместе с приложением create-react-app?

Вот мой код:

App. js

//Created by: Byron Georgopoulos
//Created on: 31/07/2020
//Last Updated on: 03/08/2020
//Description: Using Geolocation API, OpenWeatherMap API, and Fetch API, this React App displays the weather at the user current location,
//and a user can search the OpenWeatherMap database for the weather in (most) cities across the globe. 

//Import React
import React, { Component } from 'react';

//Import Fetch API
import 'isomorphic-fetch';

//Styling and React-Bootstrap
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button';
import Card from 'react-bootstrap/Card';
import Modal from 'react-bootstrap/Modal';

//Get API key from .env file
const key = process.env.REACT_APP_WEATHER_API_KEY;
console.log('API Key: ', key);

class App extends Component {
  
  constructor(props) {
    
    super(props);
    
    this.state = {
      error: null,
      isLoaded: false,
      userCity: '',
      cityInfo: [],
      showModal: false,
    };

  }

  //Use Geolocation API to find users co-ordinants
  getPos = () => {
    return new Promise (function (resolve, reject){
      navigator.geolocation.getCurrentPosition(resolve, reject);
    });
  }

  //Get Latitude & Longitude, and search OpenWeatherMap API based on location (coords)
  getLocalWeather = async (latitude, longitude) => {
    const apiCall = await fetch(`http://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${key}&units=metric`);
    const result = await apiCall.json();

    this.setState({ isLoaded: true });
    this.setState({ cityInfo: [result] });
  }

  //When Component Mounts
  componentDidMount() {

    this.getPos()
    .then((position) => {
      this.getLocalWeather(position.coords.latitude, position.coords.longitude)
    },
    (error) => {
      this.setState({
        isLoaded: true,
        error
      });
    })

  }

  //Handle user search
  handleCity = (event) => {
    let userCity = event.target.value;
    this.setState({ userCity: userCity });
  }

  //Search OpenWeatherMap API for user's city
  handleSubmit = () => {

    let userCity = this.state.userCity;
    this.refs.cityInput.value = '';

    fetch(`http://api.openweathermap.org/data/2.5/weather?q=${userCity}&appid=${key}&units=metric`)
        .then(res => res.json())
        .then(
          (result) => {
            this.setState({
              isLoaded: true,
              cityInfo: [result],
            });
          },
          (error) => {
            this.setState({
              isLoaded: true,
              error
            });
          }
        )
    
  }

  //Opens Help Modal
  openModal = () => 
  {
    this.setState({ showModal: true });
  }

  //Closes Help Modal
  closeModal = () => 
  {
    this.setState({ showModal: false });
  }

  render() {

    const error = this.state.error;
    const isLoaded = this.state.isLoaded;
    const cityInfo = this.state.cityInfo;

    if (error)
    {
      return <div>
                Error: {error.message}
              </div>;
    }
    else
    if (!isLoaded)
    {
      return <div className='LoadingMsg'>
                
                <br></br>
                <h2>Welcome to Open Weather Map API</h2>
                <hr></hr>
                <h5>Finding your location...</h5>
                <h6>Please 'Allow Location Access' in your browser to continue...</h6>
                <hr></hr>
                <br></br>

            </div>;
    }
    else
    {
      return (
        <div className='App'>
  
          <br></br>
          <h2>Open Weather Map API : Find the weather in your city.</h2>
          <hr></hr>
          <h6>This was created by Byron Georgopoulos for <a href='https://www.hyperiondev.com/' target='_blank'>HyperionDev</a> (L02T14) using
               React Components. It uses the <a href='https://openweathermap.org/api' target='_blank'>Open Weather Map API</a> and 
               the <a href='https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API' target='_blank'>Geolocation API</a> to first find 
               your current location and display the weather in your city (if access is allowed by the user), and a search bar to find the weather
              for over 200.000 cities worldwide thereafter.</h6>
          <hr></hr>
          <br></br>

          <Container>
            <Row>
              <Col sm={5}>
                <br></br>
                <br></br>
                <br></br>
                <br></br>
                <br></br>
                <Form id='cityForm'>
                  <Form.Group>
                    <Form.Label>Please Enter A City:</Form.Label>
                    <Form.Control onChange={this.handleCity} type='text' placeholder='e.g. Johannesburg' ref='cityInput' />
                    <br></br>
                    <Container>
                      <Row>
                        <Col>
                          <Button onClick={this.handleSubmit} variant='primary'>Search City</Button>
                        </Col>
                        <Col>
                          <Button onClick={this.openModal} id='helpBtn' variant='info'>Help / FAQ</Button>
                        </Col>
                      </Row>
                    </Container>
                  </Form.Group>
                </Form>
              </Col>
              <Col sm={7}>
                    {cityInfo.map(item => (
                      <Card id='weatherCard'>
                        <Card.Body>
                          <Card.Title><h3>Weather for <b>{item.name}</b>, {item.sys.country}.</h3></Card.Title>
                          <hr></hr>
                          <Card.Text><h5>It is currently: ±{Math.round(item.main.temp)}° C.</h5></Card.Text>
                          <Card.Text><h5>It feels like: ±{Math.round(item.main.feels_like)}° C.</h5></Card.Text>
                          <Card.Text><h5>The weather is: {item.weather[0].main}.</h5></Card.Text>
                          <Card.Text><h5>Sky Description: {item.weather[0].description}.</h5></Card.Text>
                          <Card.Text><h5>Humidity is at: {item.main.humidity}%.</h5></Card.Text>
                          <Card.Text><h5>Wind Speed is at: {item.wind.speed}m/s.</h5></Card.Text>
                        </Card.Body>
                      </Card>
                    ))}
              </Col>
            </Row>
          </Container>
          <br></br>
          <hr></hr>
          <br></br>
          
          <Modal id='helpModal' show={this.state.showModal} onHide={this.closeModal} animation={true} centered>
            <Modal.Body>
              <h4 id='modalHeading'>Help : Searching For A City</h4>
              <hr></hr>
              <Container>
                <Row>
                  <Col sm={1}>
                    <h6>1. </h6>
                  </Col>
                  <Col sm={11}>
                    <h6>You can only search cities in the input field. No countries, co-ordinates, provinces, states, etc.</h6>
                  </Col>
                </Row>
                <Row>
                  <Col sm={1}>
                    <h6>2. </h6>
                  </Col>
                  <Col sm={11}>
                    <h6>You can only search a cities FULL NAME. For example, LA ≠ Los Angeles, or JHB ≠ Johannesburg.</h6>
                  </Col>
                </Row>
                <Row>
                  <Col sm={1}>
                    <h6>3. </h6>
                  </Col>
                  <Col sm={11}>
                    <h6>That being said, searching for a city is NOT case sensitive. For example, los angeles = Los Angeles, or johannesburg = Johannesburg.</h6>
                  </Col>
                </Row>
                <Row>
                  <Col sm={1}>
                    <h6>4. </h6>
                  </Col>
                  <Col sm={11}>
                    <h6>± : Temperatures are rounded to the nearest whole number.</h6>
                  </Col>
                </Row>
                <Row>
                  <Col sm={1}>
                    <h6>5. </h6>
                  </Col>
                  <Col sm={11}>
                    <h6>Temperatures are in Degrees Celcius.</h6>
                  </Col>
                </Row>
              </Container>
            </Modal.Body>
            <Modal.Footer>
              <Button variant='danger' onClick={this.closeModal}>Close</Button>
            </Modal.Footer>
          </Modal> 

        </div>
      );
    }
  }
}

export default App;

package. json

    {
      "name": "weather-api",
      "version": "0.1.0",
      "private": true,
      "dependencies": {
        "@testing-library/jest-dom": "^4.2.4",
        "@testing-library/react": "^9.5.0",
        "@testing-library/user-event": "^7.2.1",
        "bootstrap": "^4.5.1",
        "es6-promise": "^4.2.8",
        "isomorphic-fetch": "^2.2.1",
        "react": "^16.13.1",
        "react-bootstrap": "^1.3.0",
        "react-dom": "^16.13.1",
        "react-scripts": "3.4.1"
      },
      "scripts": {
        "start": "react-scripts start",
        "build": "react-scripts build",
        "test": "react-scripts test",
        "eject": "react-scripts eject"
      },
      "eslintConfig": {
        "extends": "react-app"
      },
      "browserslist": {
        "production": [
          ">0.2%",
          "not dead",
          "not op_mini all"
        ],
        "development": [
          "last 1 chrome version",
          "last 1 firefox version",
          "last 1 safari version"
        ]
      }

}

.env (без пробелов до или после =, без кавычек, и X - это мой ключ API)

REACT_APP_WEATHER_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Другое на заметку:

  1. macOS Catalina 10.15.6: Macbook Pro 2017
  2. Использование VS Code
  3. React- Bootstrap установлен
  4. Использование Firefox, чтобы попытаться запустить приложение (через 'npm start' в моем терминале)

Извините за длинный пост, и если я что-то упустил. Все еще очень новичок во всем этом, особенно в Stack Overflow. Спасибо.

Ответы [ 3 ]

0 голосов
/ 05 августа 2020

React читает / создает env при сборке, поэтому вам нужно npm run start каждый раз, когда вы изменяете файл .env, чтобы переменные обновлялись.

И вам не нужно устанавливать другие пакеты, поскольку CRA (create-response-app) уже поставляется с dotenv

Вы должны использовать этот {process.env. REACT_APP_WEATHER_API_KEY} везде, где существует ваш ключ.

0 голосов
/ 05 августа 2020
  1. Переменные среды в приложении Create React. Мы можем добавить в наш проект c переменные среды, объявив их в локальном файле JS. По умолчанию у нас есть NODE_ENV, определенный для нас CRA, и мы можем добавлять любые другие переменные среды, начиная с REACT_APP _.

ВНИМАНИЕ: не храните какие-либо секреты (например, закрытые ключи API) в вашем приложении React ! Переменные среды встроены в сборку, что означает, что любой может просматривать их, проверяя файлы вашего приложения.

Переменные среды встраиваются во время сборки. Поскольку приложение Create React создает пакет stati c HTML / CSS / JS, он не может читать их во время выполнения.

Примечание. Вы должны создавать собственные переменные среды, начинающиеся с REACT_APP_. Любые другие переменные, кроме NODE_ENV, будут проигнорированы, чтобы избежать случайного раскрытия секретного ключа на машине, который может иметь то же имя. Изменение любых переменных среды потребует перезапуска сервера разработки, если он работает.

Управление переменными среды в файлах .env Мы можем создать файл с именем .env, в котором мы можем хранить наши переменные среды. Этот файл .env будет рассматриваться как файл по умолчанию для определения постоянных переменных среды.

Теперь нам нужно создать другие файлы .env для поддержки промежуточных и производственных сред. Итак, давайте создадим файлы .env.staging и .env.production.

Таким образом, файлы будут выглядеть так:

// **.env**

REACT\_APP\_TITLE = "My Awesome App"
REACT\_APP\_SESSION\_TIME = "60"

// **.env.staging**

REACT\_APP\_API\_BASE\_URL = "https://app.staging.com/api/"

// **.env.production**

REACT\_APP\_API\_BASE\_URL = "https://app.prod.com/api/"
Установить пакет env-cmd Теперь, когда у нас есть готовые отдельные файлы env, мы можем использовать их для создания c сборок, специфичных для среды. Для этого мы будем использовать npm пакет * env-cmd *.

env-cmd

Это простая программа узла для выполнения команд с использованием среды из файла env . Установите этот пакет с помощью следующей команды:

**npm install env-cmd**

Создание команд для создания специфичных для среды c сборок Теперь откройте файл package. json и добавьте ниже скрипты,

"scripts": {"start": "react-scripts start ", " start: staging ":" env-cmd -f .env.staging, запуск сценариев реакции ", " start: prod ":" env-cmd -f .env.production response -scripts start ", " build ":" react-scripts build ", " build: staging ":" env-cmd -f .env.staging, response-scripts build ", "build: prod": "env-cmd -f .env.production react-scripts build","test": "response-scripts test", "eject": "react-scripts eject"}

источник https://dev.to/rishikeshvedpathak/react-environment-specific-builds-using-env-with-cra-and-env-cmd-296b

0 голосов
/ 05 августа 2020

Вам также следует установить пакет:

npm i dotenv
...