Выполнение вызова API и обновление состояния, но получение неопределенного

Я делаю вызов API и успешно обновляю состояние. Данные из API выглядят так:

{ 
 "data": [{"name": string}, {"name":string}, ...]
}

Я делаю создание API в моем didMount метод жизненного цикла. Просто для тестирования я регистрирую состояние, используя onClick на кнопке. Когда у меня есть заявление о регистрации, как это Js.log(self.state.projects[0);первый объект в массиве регистрируется так:

{ name: "Flaherty" }

Тогда я регистрируюсь для name свойство как это такJs.log(self.state.projects[0].name, Я жду "Flaherty" чтобы войти, но только undefined регистрируется.

Я также пытался сделать name из состояния вот так: <div>(ReasonReact.stringToElement(self.state.projects[0].name)</div> и я получаю эту загадочную ошибку: не могу прочитать свойство '__reactInternalInstance$fljwvs5b8u5' с нулевым значением. Я думаю из-за противоречивого состояния.

Я могу проверить в средствах разработки, что состояние действительно обновлено. Я озадачен, почему тогда я не могу получить доступ к name недвижимость в state.projects[0], Пожалуйста, сообщите, если у кого-то есть подсказка!

Я новичок в ReasonReact, возможно я делаю вызов API и обновляю состояние не лучшим образом. Если у кого-то есть какие-либо предложения по более эффективному способу - я приветствую ваши отзывы. Благодарю.

Вот как выглядит мой компонент:

type project = {
  name: string
};

type state = {
  projects: array(project)
};

type action =
  | FetchData(array(project))
  | Search;

let component = ReasonReact.reducerComponent("Projects");
let make = (_children) => {
  ...component,
  initialState: () => {
    projects: [||]
  },
  reducer: (action, _state) =>
    switch(action) {
    | FetchData(data) => ReasonReact.Update({projects: data})
    | Search => ReasonReact.NoUpdate
    },
  didMount: (self) => {
    Js.Promise.(
        Axios.get("/api/projects")
        |> then_((response) => resolve(self.send(FetchData(response##data))))
        |> ignore
    );
    ReasonReact.NoUpdate;
  },
  render: (self) =>
    <div>
      <div>
        <span>(ReasonReact.stringToElement("SEARCH"))</span>
        <input _type="text"/>
      </div>
      <div>
        <button onClick=((_) => Js.log(self.state.projects[0].name))>(ReasonReact.stringToElement("log data"))</button>
      </div>
      <div>
        (ReasonReact.arrayToElement(
          Array.mapi((i, project) => {
            <div key=string_of_int(i) >(ReasonReact.stringToElement(project.name))</div>
          }, self.state.projects)
        ))
      </div>
    </div>
};

2 ответа

Благодаря тому, что @rickyvetter нашел время, чтобы помочь и проработал это вместе со мной, проблема была определена как определение типа для данных из API. Вместо того, чтобы быть определенным как запись, он должен быть определен как объект javascript следующим образом:

type project = {
  .
  "name": string
};

Строки вокруг имени свойства - сахар.

Тогда вместо использования точечной нотации следует использовать средство доступа к объекту js. Вот так:

self.send.projects[0]##name

Проблема заключается в несовместимости типов.

type project = {
  name: string
};

тип записи и данные, которые API предоставляет вам, это объекты JS, которые несовместимы:

{"name": string}

Axios API предоставляет вам объект JS неизвестной формы и в этой строке:

|> then_((response) => resolve(self.send(FetchData(response##data))))

Причина в том, что данные ответа ## являются массивом записей, а не массивом объектов, которыми они на самом деле являются. Это можно исправить, изменив тип project:

type project = {.
  "name": string
};

чтобы указать, что это на самом деле объект JS, или путем преобразования в запись из ответа API с помощью чего-то вроде:

let projObjToRecord = projObj => {name: projObj##name};

и отображение объектов для их преобразования. Если вы выберете первое, то вам также придется обновить сайты вызовов, чтобы использовать ## вместо . доступ.

Другие вопросы по тегам