How would you do file uploads in a React-Relay app?

后端 未结 5 1219
时光说笑
时光说笑 2020-12-30 03:45

A file upload seems like a mutation. It\'s often accompanied by other data. But it\'s a big binary blob, so I\'m not sure how GraphQL can deal with it. How would you inte

5条回答
  •  醉梦人生
    2020-12-30 04:01

    First you need to write the Relay update in your frontend component. Like this:

    onDrop: function(files) {
      files.forEach((file)=> {
        Relay.Store.commitUpdate(
          new AddImageMutation({
            file,
            images: this.props.User,
          }),
          {onSuccess, onFailure}
        );
      });
    },
    

    And then follow by implementing the mutation on the frontend:

    class AddImageMutation extends Relay.Mutation {
       static fragments = {
         images: () => Relay.QL`
           fragment on User {
             id,
           }`,
         };
    
       getMutation() {
         return Relay.QL`mutation{ introduceImage }`;
       }
    
       getFiles() {
         return {
           file: this.props.file,
         };
       }
    
       getVariables() {
         return {
           imageName: this.props.file.name,
         };
       }
    
       getFatQuery() {
         return Relay.QL`
           fragment on IntroduceImagePayload {
             User {
               images(first: 30) {
                 edges {
                   node {
                     id,
                   }
                 }
               }
             },
             newImageEdge,
           }
         `;
       }
    
       getConfigs() {
         return [{
           type: 'RANGE_ADD',
           parentName: 'User',
           parentID: this.props.images.id,
           connectionName: 'images',
           edgeName: 'newImageEdge',
           rangeBehaviors: {
             '': 'prepend',
           },
         }];
       }
     }
    

    And last, implement the handler on the server/schema.

    const imageMutation = Relay.mutationWithClientMutationId({
      name: 'IntroduceImage',
      inputFields: {
        imageName: {
          type: new GraphQL.GraphQLNonNull(GraphQL.GraphQLString),
        },
      },
      outputFields: {
        newImageEdge: {
          type: ImageEdge,
          resolve: (payload, args, options) => {
            const file = options.rootValue.request.file;
            //write the image to you disk
            return uploadFile(file.buffer, filePath, filename)
            .then(() => {
              /* Find the offset for new edge*/
              return Promise.all(
                [(new myImages()).getAll(),
                  (new myImages()).getById(payload.insertId)])
              .spread((allImages, newImage) => {
                const newImageStr = JSON.stringify(newImage);
                /* If edge is in list return index */
                const offset = allImages.reduce((pre, ele, idx) => {
                  if (JSON.stringify(ele) === newImageStr) {
                    return idx;
                  }
                  return pre;
                }, -1);
    
                return {
                  cursor: offset !== -1 ? Relay.offsetToCursor(offset) : null,
                  node: newImage,
                };
              });
            });
          },
        },
        User: {
          type: UserType,
          resolve: () => (new myImages()).getAll(),
        },
      },
      mutateAndGetPayload: (input) => {
        //break the names to array.
        let imageName = input.imageName.substring(0, input.imageName.lastIndexOf('.'));
        const mimeType = input.imageName.substring(input.imageName.lastIndexOf('.'));
        //wirte the image to database
        return (new myImages())
        .add(imageName)
        .then(id => {
        //prepare to wirte disk
          return {
            insertId: id,
            imgNmae: imageName,
          };
        });
      },
    });
    

    All the code above you can find them in my repo https://github.com/bfwg/relay-gallery There is also a live demo https://fanjin.io

提交回复
热议问题