【问题标题】:React Relay createFragmentContainer and QueryRenderer data flowReact Relay createFragmentContainer 和 QueryRenderer 数据流
【发布时间】:2020-08-22 11:50:39
【问题描述】:

我一直在研究中继文档中针对 QueryRenderer https://relay.dev/docs/en/query-renderer 和 FragmentContainer https://relay.dev/docs/en/fragment-container 的示例

我对包装在 HOC createFragmentContainer 中的组件如何访问数据感到困惑。

我有一个顶级 QueryRenderer:

function renderFunction({error, props}) {
...
  if (props) {
    // Added todoList as a prop with a distinct name from tdlist which
    // is meant to be passed in by createFragmentContainer
    return <TodoList todoList = {props.todoList} />
  }
...
}
export default function ContainerWithQueryRenderer() {
  return (
    <QueryRenderer
      environment={environment}
      query={graphql`
        query ContainerWithQueryRenderer_Query {
          todoList {
            title
            todoListItems { text isComplete}
          }
        }`}
      render = { renderFunction }
    />
  );
}

还有一个 TodoList 组件,它定义了 graphql 片段中需要哪些数据:

import React from 'react';
import TodoItem from './TodoItem.js';
import { createFragmentContainer } from 'react-relay';
import graphql from 'babel-plugin-relay/macro';
function TodoList(props) {
  console.log('TodoList props:',props);
  if (props && props.todoList && props.todoList.todoListItems && props.todoList.title) {
    return (
      <div className='list-container'>
        <div className='list-header'>
          <div className='list-header-label'>{props.todoList.title}</div>
        </div>
        <div className='list'>{props.todoList.todoListItems.map( (item, key) => <TodoItem key = {key} item={item} />)}</div>
      </div>
    );
  } else {
    return null;
  }
}
export default createFragmentContainer(TodoList,{
  tdlist: graphql`
    fragment TodoList_tdlist on TodoList {
      title
      todoListItems {
        ...TodoItem_item
      }
    }
  `,
})

还有一个子 TodoListItem

import React from 'react';
import { createFragmentContainer } from 'react-relay';
import graphql from 'babel-plugin-relay/macro';
function TodoItem(props) {

  return <div className='list-item'>
      <div className='list-item-label'>{props.item.text}</div>
      {props.item.isComplete ?<div className='list-item-buttons'>Done</div>:null}
    </div>
}

export default createFragmentContainer( TodoItem,{
  item: graphql`
    fragment TodoItem_item on Todo {
      text isComplete
    }
  `
});

我的理解是 TodoList 的 createFragmentContainer 将从 TodoList_tdlist 片段注入数据作为 TodoList props.tdlist),根据 graphql 查询的形状进行整形。

但是,这似乎没有发生。我在控制台中收到警告:

Warning: createFragmentSpecResolver: Expected prop `tdlist` to be supplied to `Relay(TodoList)`, but got `undefined`. Pass an explicit `null` if this is intentional.

如果不传入tdlist,createFragmentContainer的作用是什么?

我尝试通过更改显式传递 todoList 数据 返回 到 返回 (createFragmentContainer 传入的相同道具名称,我(可以理解)得到不同的错误:

Warning: RelayModernSelector: Expected object to contain data for fragment `TodoList_tdlist`, got `{"title":"Your to-do list","todoListItems":[{"text":"Brush teeth","isComplete":false},....

我认为我困惑的根源在于不了解定义数据依赖关系的片段如何与 QueryRenderer 交互。我是否需要定义查询以提取所有可能需要的数据,关键是中继只会通过查看现在正在呈现的组件的 graphql 片段来查询所需的内容,并且会重新查询是否更改,在获取新数据时更新道具?

我是否需要将 props 作为 props 显式传递给片段容器,或者如果它们是请求其数据的 QueryRenderer 的后代,createFragmentContainer 是否能够通过中继环境访问它?

这是我的 graphql.schema 来提供帮助:

type Query {
  todoList: TodoList!
}
type Todo {
  text: String!
  isComplete: Boolean!
}
type TodoList {
  title: String!
  todoListItems: [Todo]!
}

【问题讨论】:

  • 我了解到这里的部分问题是我的 QueryRenderer 不使用 GraphQLfragment,它只使用一个 graphQL 查询并命名它所需的字段及其后代。通过不使用 GraphQL 命名查询,我不提供 QueryRenderer 的数据和 Fragment Container 的数据之间的链接。

标签: react-relay


【解决方案1】:

您必须在 QueryRenderer 中命名后代片段容器的 GraphQL 片段。在没有识别片段的情况下,react-relay 在 QueryRenderer 和后代 FragmentContainer 组件之间没有中继链接。在您的问题中,传递给 QueryRenderer 的 query 道具是

query ContainerWithQueryRenderer_Query { todoList { title todoListItems { text isComplete }}}

而不是

query ContainerWithQueryRenderer_Query { TodoList_tdlist }

此外,由于 QueryRenderer 与 Fragment Container 一起工作,因此在 Query Renderer 中迭代 todoListItems 并为 TodoItem_item 使用片段会更简单。因此下面我合并了上面的&lt;ContainerWithQueryRenderer /&gt;&lt;TodoList /&gt;

这种方法有效:

TodoListWithQueryRenderer.js:

function renderFunction({error, props}) {
...
  if (props) {
    return (
        <div>
          <div>
            <div>{props.todoList.title}</div>
          </div>
          <div>{props.todoList.todoListItems.map( (item, key) => <TodoItem key = {key} item={item} /> )}</div>
        </div>
      );
  }
...
}
export default function TodoListWithQueryRenderer() {
  return (
    <QueryRenderer
      environment={environment}
      query={graphql`
        query TodoListWithQueryRenderer_Query { todoList {todoListItems {...TodoItem_item } title} }
      `}
      render = { renderFunction }
    />
  );
}

只需要一个后代组件,因为上面将 ContainerWithQueryRenderer 与 TodoList 组件合并。

TodoItem.js:

import React from 'react';
import { createFragmentContainer } from 'react-relay';
import graphql from 'babel-plugin-relay/macro';
function TodoItem(props) {

  return <div>
      <div>{props.item.text}</div>
      {props.item.isComplete ? <div>Done</div> : null}
    </div>
}

export default createFragmentContainer( TodoItem,{
  item: graphql`
    fragment TodoItem_item on Todo {
      text isComplete
    }
  `
});

【讨论】:

    猜你喜欢
    • 2018-12-09
    • 2018-01-29
    • 2018-05-12
    • 2019-04-16
    • 2018-03-27
    • 2018-02-12
    • 2019-12-28
    • 2021-04-28
    • 2021-04-28
    相关资源
    最近更新 更多