【问题标题】:Redux - should I get product details from state or api call?Redux - 我应该从状态或 api 调用中获取产品详细信息吗?
【发布时间】:2021-08-02 14:38:37
【问题描述】:

在一个 react 和 redux 应用程序中,我获取了用户的所有产品并将其存储在用户首次登录并进入主页时的状态。然后,用户可以查看其产品的某个单独页面,并可能在其中编辑内容。

因此,在详细信息页面上,我可以使用状态列表中已存储的产品。它避免了需要进行另一个 api 调用,据我所知,这是“反应方式”。它快速高效。

但我也看到了这样做的缺点:

  • 如果用户直接访问 hi.com/product/1 的 url,则该商店尚未填充他的产品数据,则该商店不可用。那该怎么办?有条件地在商店中加载当前产品的数据?重定向到主页?听起来很乱。
  • 它会强制系统最初加载每个产品的详细信息。产品不多就好,但多就不好说了。更多数据要通过网络发送,更多数据要存储。

【问题讨论】:

    标签: reactjs redux react-redux


    【解决方案1】:

    要处理这种特定情况,您可以为您的路由添加 Content Guard(或 Route Guard),专门检查您所需的数据是否存在于 Redux 状态。

    你可以在这里使用一个不错的库react-router-guards

    或者您始终可以创建自己的逻辑功能组件,以根据您的页面管理您的路由和基本 API 调用

    举例

    如果您直接访问 hi.com/product/1

    1) 当你使用 react-router-guards 时

    const requireStates = (to, from, next) => {
      if (to.meta.auth) {
        if (getIsLoggedIn()) {
          let actualPath = to.location.pathname.split("/");
          if(actualPath[1] === "product") {
           if(isProductAPIDataPresent)// here check if redux state have that particular data present
            {
              next();
            } else {
               fetch(); // get Product API data 
               store(); // store it in redux states
               next();
            }
          } else {
               next();
          }
        }
        next.redirect('/login');
      } else {
        next();
      }
    };
    
    const App = () => (
      <BrowserRouter>
        <GuardProvider guards={[requireStates]} loading={Loading} error={NotFound}>
          <Switch>
            <GuardedRoute path="/product/:productID" exact component={Product} meta={{ auth: true }} />
            <GuardedRoute path="/home" exact component={Home} meta={{ auth: true }} />
            <GuardedRoute path="/login" component={Login} />
          </Switch>
        </GuardProvider>
      </BrowserRouter>
    );
    

    2) 当你想构建自己的功能逻辑时(你可以只做一个功能组件,它会返回一些基本的真假情况)

       const requireStates = (tprops) => {
                 let next = {
                   isAllowed: true,
                   newLocation: "/",
                 }
                  if (props.meta.auth) {
                    if (getIsLoggedIn()) {
                      let actualPath = props.location.pathname.split("/");
                      if(actualPath[1] === "product") {
                        if(isProductAPIDataPresent)// here check if redux state have that particular data present
                        {
                          return next;
                        } else {
                           fetch(); // get Product API data 
                           store(); // store it in redux states
                           return next;
                        }
                     } else {
                      return next;
                    }
                    
           
                    next.isAllowed = false;
                    next.newLocation = "/login"
                    return next;
                  } else {
                    return next;
                  }
                };
    

    您还需要制作一个父组件(所有路由通用,它可以是布局组件),它将在继续处理该特定路由组件或子组件之前呈现

    所以在那个父组件中,你可以像这样注入上面的逻辑

      componentDidMount = async () => {
        await requireStates(this.props).then((result) => {
          if (!result.isAllowed) {
            window.location.replace(result.newLocation);
          }
        });
      };
    

    注意*:对于第二种解决方案,您可以通过多种方式实现所需目标

    【讨论】:

    • 非常有趣和详细的答案,谢谢!我的问题中的第二点呢,发送大量我可能不需要的数据不是性能问题吗?
    • 这里我认为你已经将数据直接存储在一个单一的 redux 状态,当你有大量数据或者可能是深度嵌套数据的情况下,你将面临从中获取特定数据的性能问题(您可以通过使用各种有效的算法来解决这个问题)。所以在这个特殊的情况下,我个人使用 IndexDB 来存储和管理我的状态。 IndexDB 通过索引帮助存储您的数据,稍后,您可以有效地获取它,您还可以使用各种方法保护此存储以确保数据安全。考虑到您的数据复杂性,您可以处理您的案例。
    猜你喜欢
    • 1970-01-01
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    • 2015-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多