簡體   English   中英

如何處理中繼突變中未解決的道具?

[英]How to handle unresolved props in relay mutations?

我創建了一個Relay.Mutation ,它應該觸發User對象上的更新:

class UserMutation extends Relay.Mutation {
    public getMutation() {
        return Relay.QL`mutation {saveUser}`;
    }

    public getVariables() {
        return {
            id: this.props.user.id,
            loginName: this.props.user.loginName,
            firstName: this.props.user.firstName,
            lastName: this.props.user.lastName,
            mail: this.props.user.mail
        }
    }

    public getFatQuery() {
        return Relay.QL`
            fragment on UserPayload {
                user {
                    id,
                    loginName,
                    firstName,
                    lastName,
                    mail
                }
            }
        `;
    }

    public getConfigs() {
        return [{
            type: "FIELDS_CHANGE",
            fieldIDs: {
                user: this.props.user.id
            }
        }];
    }

    static fragments = {
        user: () => Relay.QL`
            fragment on User {
                id,
                // I initially had only id here
                loginName,
                firstName,
                lastName,
                mail
            }
        `
    }
}

我在組件UserDetails使用這種突變,如下所示:

// I initially passed this.props.user to the mutation
this.props.relay.commitUpdate(new UserMutation({ user: this.state.user })

執行時,中繼將user僅設置了id身份傳遞到后端,沒有任何其他屬性。 由於輸入變量缺少其他字段,因此不執行該突變。

在調試了突變之后,我看到this.props.user在除id之外的所有字段上都設置了undefined 但是, this._unresolvedProps.user是正確設置所有字段的user

當我更改變異的代碼並將所有this.props替換為this._unresolvedProps ,所有必要的數據都將傳輸到后端,並且變異得以執行而沒有任何錯誤。 前端緩存似乎也已正確更新(諸如firstName類的字段在其他組件中已更新)。 但是我不希望這是正確的方法。

我想念什么?

更新

UserDetails組件加載諸如loginName類的用戶數據,並提供文本框來更改這些屬性。 相應的中繼容器如下所示:

export default Relay.createContainer(UserDetails, {
    fragments: {
        user: () => Relay.QL`
            fragment on User {
                id,
                loginName,
                firstName,
                lastName,
                mail,
                roles {
                    id,
                    name
                },
                ${UserMutation.getFragment("user")}
            }
        `
    }
});

我在文本輸入處理程序中處理文本框更改...

public handleTextInput(fieldName: string, event: any) {
    let user = this.state.user;

    switch (fieldName) {
        case "loginName": {
            user.loginName = event.target.value;
            break;
        }
        case "firstName": {
            user.firstName = event.target.value;
            break;
        }
        case "lastName": {
            user.lastName = event.target.value;
            break;
        }
        case "mail": {
            user.mail = event.target.value;
            break;
        }
    }

    this.setState({ user: user });
}

...然后在提交處理程序中提交表單,現在我將this.state.user傳遞給該this.state.user

public handleSubmit(e: any) {
    e.preventDefault();
    this.props.relay.commitUpdate(new UserMutation({ user: this.state.user }), {
        onSuccess: (response: any) => {
            this.setState({ user: response.saveUser.user });
        }
    });
}

我使用C#后端: graphql-dotnet 這是我為突變定義的:

public class ApplicationSchema : Schema
{
    public ApplicationSchema()
    {
        this.Query = new ApplicationQuery();
        this.Mutation = new ApplicationMutation();
    }
}

public class ApplicationMutation : ObjectGraphType
{
    public ApplicationMutation()
    {
        this.Name = "Mutation";

        // save a user
        this.Field<UserPayloadType>(
            "saveUser",
             arguments: new QueryArguments(
             new QueryArgument<NonNullGraphType<UserInputType>>
             {
                 Name = "input",
                 Description = "the user that should be saved"
             }),
            resolve: context =>
                {
                    var userInput = context.Argument<UserInput>("input");
                    var clientMutationId = userInput.ClientMutationId;

                    var user = MemoryRepository.UpdateUser(new User()
                    {
                        Id = userInput.Id,
                        LoginName = userInput.LoginName,
                        FirstName = userInput.FirstName,
                        LastName = userInput.LastName,
                        Mail = userInput.Mail
                    });

                    return new UserPayload()
                    {
                        ClientMutationId = clientMutationId,
                        User = user
                    };
                });
    }
}

public class UserInputType : InputObjectGraphType
{
    public UserInputType()
    {
        this.Name = "UserInput";

        this.Field<NonNullGraphType<StringGraphType>>("id", "The id of the user.");
        this.Field<NonNullGraphType<StringGraphType>>("loginName", "The login name of the user.");
        this.Field<NonNullGraphType<StringGraphType>>("firstName", "The first name of the user.");
        this.Field<NonNullGraphType<StringGraphType>>("lastName", "The last name of the user.");
        this.Field<NonNullGraphType<StringGraphType>>("mail", "The mail adress of the user.");

        this.Field<NonNullGraphType<StringGraphType>>("clientMutationId", "react-relay property.");
    }
}

public class UserPayloadType : ObjectGraphType
{
    public UserPayloadType()
    {
        this.Name = "UserPayload";

        this.Field<NonNullGraphType<UserType>>("user", "The user.");

        this.Field<NonNullGraphType<StringGraphType>>("clientMutationId", "react-relay property.");
    }
}

public class UserType : ObjectGraphType
{
    public UserType()
    {
        this.Name = "User";
        this.Field<NonNullGraphType<StringGraphType>>("id", "The id of the user.");
        this.Field<NonNullGraphType<StringGraphType>>("loginName", "The login name of the user.");
        this.Field<NonNullGraphType<StringGraphType>>("firstName", "The first name of the user.");
        this.Field<NonNullGraphType<StringGraphType>>("lastName", "The last name of the user.");
        this.Field<NonNullGraphType<StringGraphType>>("mail", "The mail adress of the user.");

        Field<ListGraphType<RoleType>>("roles", resolve: context => MemoryRepository.GetRolesOfUser(context.Source as DomainModel.Models.User));
    }
}

您的中繼容器是否正確提取User片段? 我在您的static fragments定義中看到用戶唯一ID片段是字段,所以我想知道您的父Relay組件是否正在全部獲取它們。

由於您的突變實際上取決於這些字段,因此請將它們添加到fragments屬性。

class UserMutation extends Relay.Mutation {
    public getMutation() { ... }

    // getVariables, FatQuery and Configs ...

    static fragments = {
      user: () => Relay.QL`
          fragment on User {
              id,
              loginName,
              firstName,
              lastName,
              mail
          }
      `
    }
}

然后嘗試將此片段包含在使用您的突變的Relay組件中。 示例React-Relay組件:

import UserMutation from 'mutations/user';

class User extends Component {
  commit(e) {
    Relay.Store.commitUpdate(
      new UserMutation({
        user: this.props.user
      })
    );
  }

  render() {
    return (
      <div>Hello</div>
    );
  }
};

export default Relay.createContainer(User, {
  fragments: {
    user: () => Relay.QL`
      fragment on User {
        ${UserMutation.getFragment('user')}
      }
    `,
  }
});

使用REQUIRED_CHILDREN並更新組件中的狀態。

您可以使用REQUIRED_CHILDREN而不是使用FIELDS_CHANGE,這將使您可以將返回的已保存對象添加到商店中。 您將要做的是像這樣設置getConfigs:

getConfigs() {
  return [{
    type: 'REQUIRED_CHILDREN',
      children: [
        Relay.QL`
          fragment on UserPayload {
            user {
              id
              loginName
              firstName
              lastName
              mail
            }
          }
        `
      ]
  }]
}

並更改您的commitUpdate,如下所示:

this.props.relay.commitUpdate(
  new UserMutation({user: this.props.user}),
  {
    onSuccess: response => this.setState({
      user: response.user,
    }),
    onError: err => console.log(err)
  }
);

如您所見,onSuccess回調使您可以調用actionCreator並將新用戶置於應用程序狀態。 您將使用應用程序中使用的任何狀態管理來執行此操作。 在這種情況下,它就是setState。

REQUIRED_CHILDREN配置用於將其他子項附加到突變查詢中。 例如,您可能需要使用它來獲取由該突變創建的新對象上的字段(並且中繼通常不會嘗試獲取該對象,因為該對象以前沒有為該對象獲取任何東西)。

由於REQUIRED_CHILDREN配置而獲取的數據未寫入客戶端存儲,但是您可以在傳遞給commitUpdate()的onSuccess回調中添加處理該數據的代碼。

在此處,有關REQUIRED_CHILDREN的文檔中有更多信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM