在React中导出异步函数的结果

时间:2018-08-22 23:15:29

标签: reactjs

我正在用.NET Core构建一个React应用,并将一些常量值放在appsettings.json文件中(不敏感),并将这些值公开为API控制器。我的想法是将API调用放在.js文件中,并将这些值公开为常量,以便在所有其他.js文件中可用。

我有以下内容:

var y = "foo";

function successCallback(resp) {
    y = resp;
    console.log(y); //shows expected value
}

async function readConfig() {
    fetch('api/ClientConfiguration')
        .then(response => {
            if (response.ok) {
                return response.json();
            } else {
                throw new Error('error...')
            }
        })
        .then(responseJson => {
            successCallback(responseJson.apiUrl);
        });
}

readConfig();

console.log(y); //shows "foo"

export const clientConfig = {
    apiUrl: y
};  

我知道提取的异步特性使const clientConfig中的属性始终具有“ foo”值。有没有一种方法可以导出我想要的值(使用此方法或其他方法)?谢谢。

2 个答案:

答案 0 :(得分:2)

这是this problem的特例。

以后可以分配它:

function successCallback(resp) {
    clientConfig.apiUrl = resp;
}
...
export const clientConfig = {
    apiUrl: null
};  

这不应该完成;在其他模块中使用模块导入时,结果可能不存在,并且无法跟踪它何时出现。

正确的方法是导出承诺:

export const clientConfig = fetch('api/ClientConfiguration')
.then(response => {
    if (response.ok) {
        return response.json();
    } else {
        throw new Error('error...')
    }
})
.then(responseJson => {
    return { apiUrl: responseJson.apiUrl };
});

答案 1 :(得分:1)

看起来这不是一种简单或优雅的方法,事物的异步特性也是如此。我要解决的方法是制作一个执行提取的组件,然后在完成后让该组件将值传递给子代。

这是一个粗略的示例。您可以使用context使其更灵活,这将允许您将值更无缝地传递到树的下方,或者使用render props可以使此处的App替换为其他任何值零件。有很多方法可以实现上述任一目的

class ClientConfigProvider extends React.Component {
  state = {
    response: null,
    error: null,
  }

  componentDidMount() {
    fetch("api/ClientConfiguration")
      .then((response) => {
        if (response.ok) {
          return response.json()
        } else {
          this.setState({ error: "oops" })
        }
      })
      .then((response) => {
        this.setState({ response })
      })
  }

  render() {
    if (error) {
      return <div>Error while fetching config: {this.state.error}</div>
    }
    if (response) {
      return <App apiUrl={this.state.response.apiUrl} />
    }
    return <div>Loading...</div>
  }
}