You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ReasonReact应用中从API获取数据?

在ReasonReact中从API获取数据并渲染

嘿,我完全懂你的困惑——ReasonReact的官方文档确实在API请求这块讲得比较简略,我当初刚上手的时候也找了好久才摸清楚门道。其实实现起来并不复杂,咱们一步步来拆解:

核心思路

在ReasonReact中获取API数据,本质上和React逻辑一致:

  • 用**状态(state)**管理加载状态、返回数据和错误信息
  • 直接调用JS原生的fetch API发起请求(Reason可以无缝调用JS API)
  • 借助Js.Promise处理异步逻辑,请求完成后更新组件状态
  • 根据状态渲染对应的UI(加载中、数据展示、错误提示)

完整代码示例(函数组件 + Hooks)

1. 定义状态与数据类型

首先用Reason的静态类型系统约束数据结构,保证类型安全:

// 定义API返回的单条数据类型
type post = {
  id: int,
  title: string,
};

// 定义组件状态类型
type state = {
  loading: bool,
  data: option<array<post>>, // option表示可能无数据
  error: option<string>,     // option表示可能无错误
};

2. 初始化状态并发起请求

用React.useState初始化状态,在React.useEffect0中触发异步请求:

[@react.component]
let make = () => {
  let (state, setState) = React.useState(() => {
    loading: true,
    data: None,
    error: None,
  });

  // 组件挂载时发起API请求
  React.useEffect0(() => {
    Js.Promise.(
      // 调用JS原生fetch请求数据
      fetch("https://jsonplaceholder.typicode.com/posts")
      // 解析响应为JSON格式
      |> then_(response => response->json())
      // 将动态JSON转换为Reason静态类型
      |> then_(json => {
           let posts = json->Js.Json.decodeArray->Belt.Option.map(arr => 
             arr->Belt.Array.map(item => {
               // 处理可能的类型解析失败,给默认值兜底
               id: item->Js.Json.decodeInt->Belt.Option.getWithDefault(0),
               title: item->Js.Json.decodeString->Belt.Option.getWithDefault(""),
             })
           );
           // 更新状态:加载完成,存入解析后的数据
           setState(_prev => {loading: false, data: posts, error: None});
           resolve();
         })
      // 捕获请求过程中的错误
      |> catch(error => {
           setState(_prev => {loading: false, data: None, error: Some(error->Js.String.make)});
           resolve();
         })
      // 忽略Promise返回值(useEffect不需要返回Promise)
      |> ignore
    );
    None; // 无清理函数,返回None
  });

  // 根据状态渲染对应UI
  switch (state.loading, state.data, state.error) {
  | (true, _, _) => <div> {React.string("Loading...")} </div>
  | (false, Some(posts), None) => 
    <ul>
      {posts->Belt.Array.map(post => 
        <li key={string_of_int(post.id)}> {React.string(post.title)} </li>
      )->React.array}
    </ul>
  | (false, None, Some(error)) => <div> {React.string("请求出错: " ++ error)} </div>
  | (false, None, None) => <div> {React.string("暂无数据")} </div>
  }
};

关键细节说明

  • JSON类型转换:JS的JSON是动态类型,Reason是静态类型,必须用Js.Json模块的解析函数(如decodeArray、decodeInt)转换类型,并用Belt.Option处理解析失败的场景。
  • Promise处理:Reason的Js.Promise和JS Promise用法几乎一致,then_和catch链式处理异步逻辑,resolve()用来结束当前Promise链。
  • 不可变状态:Reason的记录是不可变的,更新状态时要返回完整的新记录,不能只修改单个字段。

类组件写法(兼容旧版本)

如果习惯用类组件,可以在componentDidMount生命周期中发起请求:

type post = {id: int, title: string};
type state = {loading: bool, data: option<array<post>>, error: option<string>};

class component extends React.Component(. props) {
  initialState() {
    {loading: true, data: None, error: None}
  }

  componentDidMount() {
    Js.Promise.(
      fetch("https://jsonplaceholder.typicode.com/posts")
      |> then_(response => response->json())
      |> then_(json => {
           let posts = json->Js.Json.decodeArray->Belt.Option.map(arr => 
             arr->Belt.Array.map(item => {
               id: item->Js.Json.decodeInt->Belt.Option.getWithDefault(0),
               title: item->Js.Json.decodeString->Belt.Option.getWithDefault(""),
             })
           );
           this.setState({loading: false, data: posts, error: None});
           resolve();
         })
      |> catch(error => {
           this.setState({loading: false, data: None, error: Some(error->Js.String.make)});
           resolve();
         })
      |> ignore
    );
  }

  render() {
    // 复用之前的状态判断渲染逻辑
    switch (this.state.loading, this.state.data, this.state.error) {
    // ... 省略渲染代码
    }
  }
}

这样应该就能顺利实现API数据的获取和渲染了。如果遇到特定的类型转换或者异步处理问题,随时调整细节就行!

内容的提问来源于stack exchange,提问作者Mateus Felipe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:33:14