【问题标题】:Problem with .env file and create-react-app - returns undifined.env 文件和 create-react-app 出现问题 - 返回未定义
【发布时间】:2020-08-05 12:11:16
【问题描述】:

我知道这个问题已经被问过无数次了,相信我,我已经阅读了 Stack Overflow 上的页面以及其他网站,并且显然已经阅读了文档。要么是我完全不理解的东西,要么是我错过了一些愚蠢的东西。

我创建了一个 React 应用程序(使用 npx create-react-app)来使用 API 和 fetch API 创建一个小的天气信息服务(认为它被称为那个?)。都是前端(我还没有开始学习任何后端的东西)。

我的问题是我的 .env 文件。如前所述,我做了很多研究,因此可以(希望)排除以下情况:

  1. 我的环境变量文本文件名为“.env”,位于我的根文件夹中(即与 package.json 文件和 src & public 文件夹位于同一位置)。

  2. 在 .env 文本文件中,变量以“REACT_APP_”为前缀。

  3. 我几乎可以肯定所有语法和变量名都是正确的,但这仍有可能吗?

当我将 API 密钥直接放入我的 fetch 时,一切正常,但在尝试从 .env 文件获取 API 密钥时总是未定义。我知道,因为我只做前端,如果我推送/上传到 GitHub(或其他),API 在技术上仍然可见,即使使用 .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 代码
  3. React-Bootstrap 已安装
  4. 使用 Firefox 尝试运行应用程序(通过终端中的“npm start”)

抱歉,这篇文章太长了,如果我遗漏了任何内容。对这一切仍然很陌生,尤其是 Stack Overflow。谢谢。

【问题讨论】:

    标签: reactjs environment-variables undefined create-react-app


    【解决方案1】:

    您还应该安装该软件包:

    npm i dotenv
    

    【讨论】:

      【解决方案2】:

      React 在构建时读取/创建 env,因此您每次修改 .env 文件时都需要 npm run start 以便更新变量。

      并且您不需要安装任何其他软件包,因为 CRA (create-react-app) 已经带有 dotenv

      你应该使用这个 {process.env. REACT_APP_WEATHER_API_KEY} 无论您的密钥存在哪里。

      【讨论】:

      • 当你说重启时,你的意思是关闭我的终端,然后再次输入 npm start 吗?对于第二部分:这是否意味着我不能像我一样在 App.js 中将其分配为全局变量?
      • @ByronGeorgopoulos 正确的先生。 Windows 是ctrl + c。 Mac 是control + c。如果你愿意,你可以将它分配给一个全局变量,就像你做的那样。然后从那里使用它。但是为了有一个更好的结构,我会将你所有的 API 调用移动到一个 service.js 文件中,然后你的 API 密钥可以声明为顶部,所以它只存在一次。如果您保持现在的结构,您将/可能有多个 API 调用,并且您将重复自己。让我知道这是否有意义。
      • 感谢您的回复。每当我对我的应用程序进行重大更改时,我都会完全退出我的终端(在 Mac 上为 cmd+q)并重新打开它,获取目录,然后 npm 再次启动它,以确保一切都是新鲜的。所以肯定不是这样的。将我的 API 调用转移到其他地方,只是暂时尝试了解基础知识。当你说'你应该使用这个 {process.env. REACT_APP_WEATHER_API_KEY} 无论您的密钥存在哪里。',您能详细说明一下吗?我在发布的代码中是否正确完成了它?再次感谢。
      • @ByronGeorgopoulos 将 fetch('http://api.openweathermap.org/data/2.5/weather?q=${userCity}&amp;appid=${key}&amp;units=metric') .then(res =&gt; res.json()) 替换为 fetch('http://api.openweathermap.org/data/2.5/weather?q=${userCity}&amp;appid=${process.env.REACT_APP_WEATHER_API_KEY}&amp;units=metric') .then(res =&gt; res.json()) 看看是否可行
      • 还是什么都没有。不过谢谢。
      【解决方案3】:
      1. Create React App 中的环境变量 我们可以通过在本地 JS 文件中声明它们来将环境特定变量添加到我们的项目中。默认情况下,CRA 为我们定义了 NODE_ENV,我们可以添加任何其他以 REACT_APP_ 开头的环境变量。

      警告:不要在您的 React 应用程序中存储任何秘密(例如私有 API 密钥)!环境变量嵌入到构建中,这意味着任何人都可以通过检查您的应用文件来查看它们。

      环境变量在构建时嵌入。由于 Create React App 生成一个静态 HTML/CSS/JS 包,它不可能在运行时读取它们。

      注意:您必须创建以 REACT_APP_ 开头的自定义环境变量。除了 NODE_ENV 之外的任何其他变量都将被忽略,以避免在机器上意外暴露可能具有相同名称的私钥。更改任何环境变量都需要您重新启动正在运行的开发服务器。

      1. 管理 .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/"
      
      1. 安装 env-cmd 包 现在我们已经准备好单独的 env 文件,我们可以使用它们进行环境特定的构建。我们将使用 npm 包 *env-cmd *.

      环境命令

      这是一个简单的节点程序,用于使用 env 文件中的环境执行命令。使用以下命令安装此软件包,

      **npm install env-cmd**
      
      1. 创建命令以创建特定于环境的构建 现在打开你的 package.json 文件并添加以下脚本,

        “脚本”:{ “开始”:“反应脚本开始”, "start:staging": "env-cmd -f .env.staging react-scripts start", "start:prod": "env-cmd -f .env.production react-scripts start", "build": "react-scripts build", "build:staging": "env-cmd -f .env.staging react-scripts build", "build:prod": "env-cmd -f .env.production react-scripts build", "test": "react-scripts 测试", “弹出”:“反应脚本弹出” }

      来源https://dev.to/rishikeshvedpathak/react-environment-specific-builds-using-env-with-cra-and-env-cmd-296b

      【讨论】:

      • 那么在使用 npm start 时,如果不安装 env-cmd 就无法从我的 .env 中获取 API 密钥?
      • 是的,你必须使用 npm 包
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-22
      • 2019-10-05
      • 2020-09-04
      • 2019-08-23
      • 1970-01-01
      • 1970-01-01
      • 2017-10-09
      相关资源
      最近更新 更多