【问题标题】:Skills list is not updated when new skill is added添加新技能时技能列表不更新
【发布时间】:2019-03-13 00:14:20
【问题描述】:

背景组件中有一个技能和经验的手风琴。单击技能手风琴上的标题时,模式将弹出技能表单,填写并提交后,模式关闭,技能列表应更新但未更新。我必须刷新才能看到技能列表中的变化。这是我的做法

class Background extends React.PureComponent {
  state = {
    show: false,
    componentName: null,
    activeIndex: 0
  };

  handleModal = (action, componentName) =>
    this.setState(state => ({
      show: action,
      componentName
    }));

  render() {
    const { show, activeIndex, componentName } = this.state;
    return (
      <React.Fragment>
        <ProfileWrapper>
          <Query query={BACKGROUND_QUERY}>
            {({
              data: { experiences, skills, languages, educations } = {},
              loading
            }) => {
              if (loading) {
                return <h1>Loading...</h1>;
              } else {
                return (
                  <Grid columns={2}>
                    <Accordion
                      index={1}
                      onToggle={this.handleToggle}
                      css="max-width: 100%; min-width: 200px;"
                    >
                      <Accordion.Title>
                        <Title>
                            Skills (
                            {`${skills !== undefined && skills.edges.length}`})
                        </Title>
                      </Accordion.Title>
                      <Accordion.Content>
                        <Content>
                          {skills !== undefined && skills.edges.length > 0 && (
                            <span>
                              {skills.edges.map(skill => {
                                return (
                                  <React.Fragment key={skill["node"].id}>
                                    <span key={skill["node"].id}>
                                      <Chip>{skill["node"].title}</Chip>
                                    </span>
                                  </React.Fragment>
                                );
                              })}
                            </span>
                          )}
                        </Content>
                      </Accordion.Content>
                    </Accordion>
                    <Modal
                      position="centerCenter"
                      open={show}
                      onClose={() => this.handleModal(false, null)}
                    >
                      <React.Fragment>
                        {componentName !== null &&
                          componentName === "experiences" && (
                            <Experiences experiences={experiences} />
                          )}
                        {componentName !== null &&
                          componentName === "skills" && (
                            <Skills skills={skills} />
                          )}

                      </React.Fragment>
                    </Modal>
                  </Grid>
                );
              }
            }}
          </Query>
        </ProfileWrapper>
      </React.Fragment>
    );
  }
}

export default Background;


const Skills = ({ handleSubmit, ...props }) => {
  const formSubmit = async (val, mutation) => {
    const {
      data: { skill: response }
    } = await mutation({
      variables: val
    });
    console.log('response', response);
    if (response.success) {
      props.closeModal();
      toast.success("New Skill Added!");
    }
  };
  return (
    <React.Fragment>
      <Mutation mutation={CREATE_SKILL}>
        {mutation => {
          return (
            <form onSubmit={handleSubmit(val => formSubmit(val, mutation))}>
              <Field name="title" label="Title" component={TextField} />
              <Button>
                <Button.Primary>Add Skill</Button.Primary>
                <Button.Secondary>Cancel</Button.Secondary>
              </Button>
            </form>
          );
        }}
      </Mutation>
    </React.Fragment>
  );
};

export default compose(
  reduxForm({
    form: "skillsProfile",
    enableReinitialize: true,
    destroyOnUnmount: false
  })
)(Skills);

为什么在后台组件中完成查询时,乐观的 ui 更新在这里不起作用?

【问题讨论】:

  • 当模态关闭后,您确定对 background_query 的另一个 API 调用正在发生吗?
  • 我现在检查了它,但它没有发生。当点击提交按钮后状态发生变化(显示状态,因为handleModal触发了变化),然后进入渲染函数但不调用api。
  • 如果它的 graphql 查询,我记得,graphql 缓存数据,如果查询的输入相同,它会返回缓存的数据,
  • 那我该如何乐观地更新呢?你有什么想法吗?
  • 也许您可以将选项传递给 graphql 查询。其中之一是 fetchPolicy。看看apollographql.com/docs/react/api/…

标签: javascript reactjs graphql react-apollo


【解决方案1】:

来自docs

有时当您执行突变时,您的 GraphQL 服务器和您的 Apollo 缓存会变得不同步。当您执行的更新依赖于缓存中已经存在的数据时,就会发生这种情况;例如,删除项目并将其添加到列表中。我们需要一种方法来告诉 Apollo 客户端更新项目列表的查询。这就是更新功能的用武之地!

Apollo 无法知道您的服务器在执行突变时正在执行哪种操作(添加一行或多行、删除一行等)——它所要做的只是返回的数据通过突变。它可以将这些数据与已经在缓存中的对象进行匹配并相应地更新它们,仅此而已。如果有任何字段被缓存并且由于您的突变需要更新,您需要明确告诉 Apollo 如何执行此操作(旁注,这些可能是返回 Skills 列表的字段,但它们可以实际上是受突变影响的任何其他领域)。

例如,用于添加技能的 update 函数看起来像这样:

update={(cache, { data: { addSkill } }) => {
  // assumes addSkill resolves to a single Skill
  const { skills, ...rest } = cache.readQuery({ query: BACKGROUND_QUERY });
  cache.writeQuery({
    query: BACKGROUND_QUERY,
    data: { skills: skills.concat([addSkill]), ...rest },
  });
}}

有关其他示例,请参阅文档。还值得注意的是,在使用readQuerywriteQuery 时,如果您的查询需要任何变量,则需要传入适当的变量。

虽然您可以重新获取您的查询(例如,通过将它们指定为refetchQueries 的一部分),但对于缓存的简单更新来说基本上没有必要,而且显然速度较慢而不仅仅是使用update,因为它需要再次往返于您的服务器。此外,update 甚至可以与 optimistic updates to your UI 一起使用。

【讨论】:

  • 我认为这仅适用于创建新技能并将此新技能添加到列表中,但如果我们编辑特定技能则不会工作,因为它是连接的。
  • 您的问题包括CREATE_SKILL 突变的代码,所以这就是我示例的基础。您不应该逐字使用示例,而是根据需要采用它。如果您有一个仅更新现有项目的突变,您可能不需要为它定义 update 函数。如果在发生这种变化后您没有看到 UI 更新,则说明还有其他因素在起作用。
  • @Serenity 根据您的评论,您的帖子似乎与您的实际问题不符。如果您的更新突变没有按预期更新 UI,您应该适当地更新您的代码。查看实际查询本身也很有帮助。
猜你喜欢
  • 2021-03-04
  • 2020-06-24
  • 1970-01-01
  • 2021-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多