React - 变量是undefined而不是true / false - 组件首先被渲染?

时间:2017-04-09 14:21:03

标签: javascript node.js reactjs electron

好吧,我试图实现的是一个函数,它返回一个具有不同标签的Button,具体取决于文件是否存在。到目前为止一切顺利,代码本身似乎工作正常,但顺序错误。 我所做的是打印出文件确实存在'或者'不存在'在执行实际检查的函数部分中,将boolean保存到test变量,使用所述变量确定最后返回哪个按钮。

现在发生了什么,即使第一部分打印出文件确实存在' (应将true保存到test),console.log(test)再往下一点会返回undefined,这当然导致条件不起作用。

我确信我忽略了一些非常简单的事情,但我无法弄清楚。

import React from 'react';
import RaisedButton from 'material-ui/RaisedButton';
import fs from 'fs';

var ConfigChecker = React.createClass({

  render: function(){

    var test;
    fs.open('./App.js', 'r', (err, fd) => {
      if (err) {
        if (err.code === 'ENOENT') {
          console.log('file does not exist');
          test = false;
        }

        throw err;
      }
      console.log('this should be executed first:');
      console.log('file does exist')
      test = true;
    });


    if (test)
    {
      console.log("this should be executed last:");
      console.log(test);
      return (<RaisedButton label="true" />);
    }
    else {
      console.log("this should be executed last:");
      console.log(test);
      return (<RaisedButton label="false" />);
    }
  }


});

export default ConfigChecker;

this is what gets returned in the dev console

2 个答案:

答案 0 :(得分:2)

异步调用不像您认为的那样有效。任何时候你看到一个异步的函数(期望回调,返回一个Promise)在JavaScript中使用“registerInterestIn {functionName}”在你的脑海中添加函数的名称。因此fs.open变为fs.registerInterestInOpen

考虑到这一点,您的代码现在看起来像这样:

var test;
fs.registerInterestInOpen('./App.js', 'r', ...);
// Still undefined here, we just registered an interest
// in the results of opening ./App.js ... nothing has
// actually *happened* yet.
if (test) {

} else {

}

// And when we get down here, JavaScript will actually *do*
// the opening, and call our callback with the result, when
// the operating system gets back to us with the data or an error

如何解决这个问题?

您需要使用一些React状态,以便了解组件所处的三种状态中的哪一种(等待查找文件是否存在,文件是否存在,文件是否存在)。然后,您需要将回调中的状态更改为fs.open,以告知React重新渲染您的组件:

const ConfigChecker = React.createClass({
  getInitialState() {
    return { test: null };
  },
  componentDidMount() {
    fs.open('./App.js', 'r', (err, fd) => {
      if (err && err.code === 'ENOENT') {
        console.log('file does not exist');
        return this.setState(() => { test: false});
      }
      this.setState(() => { test: true});
    });
  },
  render() {
    if (this.state.test == null) {
      return 'Loading ...';
    } else {
      return <RaisedButton label={this.state.test} />;
    }
  }

答案 1 :(得分:0)

试试这个:

import React from 'react';
import RaisedButton from 'material-ui/RaisedButton';
import fs from 'fs';

var ConfigChecker = React.createClass({

  getInitialState: function(){
    return {
      test: true
    }
  },

  // or componentWillMount() should work
  componentDidMount: function(){
    var test;
    var self = this;
    fs.open('./App.js', 'r', (err, fd) => {
      if (err) {
        if (err.code === 'ENOENT') {
          console.log('file does not exist');
          self.setState({
            test: false
          });
          // test = false;
        }

        throw err;
      }
      console.log('this should be executed first:');
      console.log('file does exist')
      self.setState({
        test: true
      });
      // test = true;
    });
  },

  render: function(){
    if (this.state.test)
    {
      console.log("this should be executed last:");
      console.log(test);
      return (<RaisedButton label="true" />);
    }
    else {
      console.log("this should be executed last:");
      console.log(test);
      return (<RaisedButton label="false" />);
    }
  }