首页 > 解决方案 > 带有反应钩子的值流

问题描述

我有X来自服务器的价值。我想公开一个类似于

interface Xclient {
    getX(): Promise<X>
}

我稍后将在我的反应功能组件中使用它。

我说类似是因为在幕后我希望它:

  1. 存储的第一个返回值(它的反应原生)
  2. 同时为更新版本的 X 发送网络调用,并在我得到响应后重新渲染组件

所以而不是Promise我可能需要Observable. 但是那么如何将它与一般反应和特别反应钩子一起使用呢?

我来自后端背景,所以可能有一些我不知道的更规范的方法。如果可能的话我真的不想用redux

标签: reactjstypescriptreact-native

解决方案


如果我理解正确,您有两个数据源(本地存储和您的 api),并且您想从本地存储中获取价值,然后从 api 中获取实际价值。所以,你应该做下一个:

import { useState } from "react";

const localProvider: Xclient = new Something();
const apiProvider: Xclient = new SomethingElse();

export function SimpleView() {
  const [state, setState] = useState("default value");

  localProvider()
    .then((response) => {
        setState(response);

        apiProvider()
            .then((actualResponse) => {
                setState(actualResponse);
            })
            .catch(/* */);
    })
    .catch(/* */);
}

但我认为没有理由同步调用它,您可以希望并行运行它:

import { useState } from "react";

const localProvider: Xclient = new Something();
const apiProvider: Xclient = new SomethingElse();

export function SimpleView() {
  const [state, setState] = useState("default value");

  localProvider()
    .then((response) => {
        setState(response);
    })
    .catch(/* */);

  apiProvider()
    .then((actualResponse) => {
        setState(actualResponse);
    })
    .catch(/* */);
}

如果你想封装这个逻辑,你可以做一个这样的函数:

import { useState } from "react";

const localProvider: Xclient = new Something();
const apiProvider: Xclient = new SomethingElse();

function getValue(localProvider, apiProvider, consumer) {
  localProvider()
    .then((response) => {
        consumer(response);
    })
    .catch(/* */);

  apiProvider()
    .then((actualResponse) => {
        consumer(actualResponse);
    })
    .catch(/* */);
}

export function SimpleView() {
  const [state, setState] = useState("default value");

  getValue(localProvider, apiProvider, setState);
}

UPD: 正如@PatrickRoberts 正确注意到我的示例包含竞争条件,此代码解决了它:

import { useState } from "react";

const localProvider: Xclient = new Something();
const apiProvider: Xclient = new SomethingElse();

function getValue(localProvider, apiProvider, consumer) {
  let wasApiResolved = false;

  localProvider()
    .then((response) => {
        if (!wasApiResolved) {
            consumer(response);
        }
    })
    .catch(/* */);

  apiProvider()
    .then((actualResponse) => {
        wasApiResolved = true;
        consumer(actualResponse);
    })
    .catch(/* */);
}

export function SimpleView() {
  const [state, setState] = useState("default value");

  getValue(localProvider, apiProvider, setState);
}

推荐阅读