Ошибка CreatMutation для нестраничного обновления на Relay/GraphQL

Ошибка CreatMutation для нестраничного обновления на Relay/GraphQL

Я создаю приложение React-Relay с Graph QL.
Ссылка на сайт https://blog.graph.cool/getting-started-with-relay-modern-46f8de6bd6ec

Вместо Post я создаю Project/Hour. Также это имеет отношение один ко многим.

Это схема графика QL

type Project @model {
  id: ID! @isUnique
  createdAt: DateTime!
  updatedAt: DateTime!
  name: String!
  description: String!
  hours: [Hour!]! @relation(name: "HoursOnProject")
}

type Hour @model {
  id: ID! @isUnique
  createdAt: DateTime!
  updatedAt: DateTime!
  amount: Int!
  description: String!
  project: Project @relation(name: "HoursOnProject")
}

Я создаю новые данные Hour для каждого Project, Когда я пытаюсь удалить DeleteMutation, он удаляет элементы без обновления страницы. Также для того, чтобы создать New Hour Item, Это использует React-Router. Это работает хорошо.

Скриншот(https://prnt.sc/h0m1lw)

Я собираюсь сделать CreateMutation, как DeleteMutation.. полностью

1) Add Form
2) Create Item when Click button( without refreshing).. Don't use react-router
3) Show total item lists

URL целевого снимка экрана (https://prnt.sc/h0ly9v)

Когда я пытаюсь нажать Add Кнопка, я получил ошибку, как это:

HourList.js:35 Uncaught TypeError: Cannot read property '__id' of undefined
    at HourList.js:35
    at Array.map (<anonymous>)
    at HourList.render (HourList.js:35)
    at finishClassComponent (react-dom.development.js:10249)
    at updateClassComponent (react-dom.development.js:10226)
    at beginWork (react-dom.development.js:10605)
    at performUnitOfWork (react-dom.development.js:12573)
    at workLoop (react-dom.development.js:12682)
    at HTMLUnknownElement.callCallback (react-dom.development.js:1299)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:1338)
    at invokeGuardedCallback (react-dom.development.js:1195)
    at performWork (react-dom.development.js:12800)
    at batchedUpdates (react-dom.development.js:13244)
    at performFiberBatchedUpdates (react-dom.development.js:1646)
    at stackBatchedUpdates (react-dom.development.js:1637)
    at batchedUpdates (react-dom.development.js:1651)
    at Object.batchedUpdatesWithControlledComponents [as batchedUpdates] (react-

proxyConsole.js:54 The above error occurred in the <HourList> component:
    in HourList (created by Relay(HourList))
    in Relay(HourList) (at HourListPage.js:48)
    in ReactRelayQueryRenderer (at HourListPage.js:39)
    in HourListPage (created by Route)
    in Route (created by withRouter(HourListPage))
    in withRouter(HourListPage) (created by Route)
    in Route (at App.js:17)
    in Switch (at App.js:15)
    in div (at App.js:14)
    in div (at App.js:12)
    in App (at index.js:11)
    in Router (created by BrowserRouter)
    in BrowserRouter (at index.js:10)

HourList.js:35 Uncaught TypeError: Cannot read property '__id' of undefined
    at HourList.js:35
    at Array.map (<anonymous>)
    at HourList.render (HourList.js:35)
    at finishClassComponent (react-dom.development.js:10249)
    at updateClassComponent (react-dom.development.js:10226)
    at beginWork (react-dom.development.js:10605)
    at performUnitOfWork (react-dom.development.js:12573)
    at workLoop (react-dom.development.js:12682)
    at HTMLUnknownElement.callCallback (react-dom.development.js:1299)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:1338)
    at invokeGuardedCallback (react-dom.development.js:1195)
    at performWork (react-dom.development.js:12800)
    at batchedUpdates (react-dom.development.js:13244)
    at performFiberBatchedUpdates (react-dom.development.js:1646)
    at stackBatchedUpdates (react-dom.development.js:1637)
    at batchedUpdates (react-dom.development.js:1651)
    at Object.batchedUpdatesWithControlledComponents [as batchedUpdates] (react-dom.development.js:1664)

proxyConsole.js:54 Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op.
Please check the code for the CreateHour component.
__stack_frame_overlay_proxy_console__ @ proxyConsole.js:54
printWarning @ warning.js:33
warning @ warning.js:57

RelayConnectionHandler.js:191 Uncaught TypeError: Cannot read property 'getLinkedRecord' of undefined
    at Object.getConnection (RelayConnectionHandler.js:191)
    at updater (CreateHourMutation.js:64)
    at RelayPublishQueue._getSourceFromPayload (RelayPublishQueue.js:171)
    at RelayPublishQueue.js:185
    at Set.forEach (<anonymous>)

Скриншот ошибки URL:

Ошибка скриншота Страница 1 (https://prnt.sc/h0m5b9)

Ошибка скриншота Страница 2(https://prnt.sc/h0m5hq

Источник проекта

в HourList.js имеются <CreateHour/> Составная часть. Когда я добавляю это, это генерирует ошибку. На самом деле я хочу сделать CreateMutation наподобие DeleteMutation без обновления страницы.

App.js

class App extends Component {
  render() {
    return (
      <div className='center w85'>
        <Header />
        <div className='ph3 pv1 background-gray'>
          <Switch>
            <Route exact path='/createproject' component={CreateProject}/>
            <Route exact path='/hours/:proj_id' component={HourListPage}/>
            <Route exact path='/createhour/:proj_id' component={CreateHour}/>
            <Route exact path='/' component={ProjectListPage}/>
           </Switch>
        </div>
      </div>
    )
  }
}

HourListPage.js

import React, { Component } from 'react'
import { withRouter } from 'react-router'
import {
    QueryRenderer,
    graphql
  } from 'react-relay'
import environment from '../Environment'
import HourList from  "./HourList"

const HourListPageQuery = graphql`
query HourListPageQuery (
  $filter: HourFilter,
  $id:ID!
)
{
  viewer {
    ...HourList_viewer
  }[enter link description here][1]
}
`


class HourListPage extends Component{
  variables = {}
  proj_id = ""
  componentWillMount(){
    this.proj_id = this.props.match.params.proj_id;
    this.variables = {
      filter: {
        project:{
          id : this.proj_id
        }
      },
      id : this.proj_id
    }
  }
    render() {
        return(
            <QueryRenderer
            environment={environment}
            query={HourListPageQuery}
            variables={this.variables}
            render={({error, props}) => {
              // console.log(props);
              if (error) {
                return <div>{error.message}</div>
              } else if (props) {
                return <HourList viewer={props.viewer}/>
              }
              return <div>Loading</div>
            }}
          />
        )
    }
  }

  export default withRouter(HourListPage)

HourList.js

import React from 'react'
import Hour from './Hour'
import {
    createFragmentContainer,
    graphql
  } from 'react-relay'
import {Link} from 'react-router-dom'
import CreateHour from "./CreateHour"
class ProjectDesc extends React.Component{

  render () {
      return (
          <div>
              <h1>{this.props.project.name}</h1>
              <h3>{this.props.project.description}</h3>
              <Link to={'/createhour/' + this.props.project.id}  className='ml1 black'>Create Hour</Link>
              <CreateHour />
          </div>
      )
  }
}
class HourList extends React.Component {
    render () {
      if(this.props.viewer.allHours.edges.length === 0){
        return (
          <div>
          <ProjectDesc project={this.props.viewer.Project}/>
          <div>No Result</div>
          </div>
        )
      }
      return (
          <div>
            <ProjectDesc project={this.props.viewer.Project}/>
              {this.props.viewer.allHours.edges.map(({node}, index) =>
                  <Hour key={node.__id} index={index} hour={node} viewer={this.props.viewer} />
              )}
          </div>
      )
  }
}

export default createFragmentContainer(HourList, graphql`
fragment HourList_viewer on Viewer {
  ...Hour_viewer
  Project(id:$id){
    id
    name
    description
  }
  allHours(filter:$filter,last: 100, orderBy: createdAt_DESC) @connection(key: "HourList_allHours", filters: []) {
    edges {
      node {
        ...Hour_hour
      }
    }
  }
}
`)

Hour.js

import React from 'react'
import {
    createFragmentContainer,
    graphql
  } from 'react-relay'

import DeleteHourMutation from '../mutations/DeleteHourMutation'

class Hour extends React.Component {
  // componentWillMount(){
  //   console.log(this.props);
  // }
  render () {
    return (
      <div className='pa3 bg-black-05 ma3'>
        <div className='flex items-center'>
            <span className='gray'>{this.props.index + 1}.</span>
            <span>{this.props.hour.description}&nbsp;</span>
            <span>{this.props.hour.amount}&nbsp; Hours</span>
            <span className='red f6 pointer dim' onClick={this._handleDelete}> Delete</span>
        </div>
      </div>
    )
  }

  _handleDelete = () => {
    DeleteHourMutation(this.props.hour.id, this.props.viewer.id)
  }
}
export default createFragmentContainer(Hour, graphql`
fragment Hour_viewer on Viewer {
  id
}
fragment Hour_hour on Hour {
  id
  description
  amount
}
`)

CreateHourMutation.js

// 1
import {
    commitMutation,
    graphql,
  } from 'react-relay'
  import {ConnectionHandler} from 'relay-runtime'
  import environment from '../Environment'
  // 2
  const mutation = graphql`
    mutation CreateHourMutation($input: CreateHourInput!) {
      createHour(input: $input) {
        hour {
          id
          createdAt
          amount
          description
        }
      }
    }
  `
  let tempHourID = 0
  // 3
  export default (description, amount, projectId, viewerId, callback) => {
    // 4
    const variables = {
      input: {
        description,
        amount,
        projectId,
        clientMutationId: ""
      },
    }
  // 5
    commitMutation(
      environment,
      {
        mutation,
        variables,
        // 6
        optimisticUpdater: (proxyStore) => {
            // 1 - create the `newHour` as a mock that can be added to the store
            const id = 'client:newHour:' + tempHourID++
            const newHour = proxyStore.create(id, 'Hour')
            newHour.setValue(id, 'id')
            newHour.setValue(description, 'description')
            newHour.setValue(parseInt(amount), 'amount')
            newHour.setValue(projectId, 'projectId')
            // 2 - add `newHour` to the store
            const viewerProxy = proxyStore.get(viewerId)

            const connection = ConnectionHandler.getConnection(viewerProxy, 'HourList_allHours', [])

            if (connection) {
              ConnectionHandler.insertEdgeAfter(connection, newHour)
            }
          },
          updater: (proxyStore) => {
            //1 - retrieve the `newHour` from the server response
            const createHourField = proxyStore.getRootField('createHour')
            // console.log(createHourField);
            const newHour = createHourField.getLinkedRecord('hour')
          // 2 - add `newHour` to the store
            const viewerProxy = proxyStore.get(viewerId)
            const connection = ConnectionHandler.getConnection(viewerProxy, 'HourList_allHours', [])

            if (connection) {
              ConnectionHandler.insertEdgeAfter(connection, newHour)
            }
          },
        // 7
        onCompleted: () => {
          callback()
        },
        onError: err => console.error(err),
      },
    )
  }

CreateHour.js

import React from 'react'
import { withRouter } from 'react-router'
import CreateHourMutation from '../mutations/CreateHourMutation'
import { QueryRenderer, graphql } from 'react-relay'
import environment from '../Environment'
import {Redirect} from 'react-router-dom'

const CreateHourViewerQuery = graphql`
query CreateHourViewerQuery {
  viewer {
    id
  }
}
`
class CreateHour extends React.Component {
    state = {
        description: '',
        amount: 0,
        projectId: '',
        submitted: false
    }
    componentWillMount(){
        if (this.props.match.params.proj_id)
            this.setState({projectId : this.props.match.params.proj_id});
    }
    render () {
        if (this.state.submitted)
            return (<Redirect to={"/hours/" + this.state.projectId} />)

        return (
            <QueryRenderer
                environment={environment}
                query={CreateHourViewerQuery}
                render={({error, props}) => {
                    if (error) {
                        return <div>{error.message}</div>
                    } else if (props) {
                    return (
                        <div className='w-100 pa4 flex justify-center'>
                        <div style={{ maxWidth: 400 }} className=''>
                            <input
                            className='w-100 pa3 mv2'
                            value={this.state.description}
                            placeholder='Description'
                            onChange={(e) => this.setState({description: e.target.value})}
                            />
                            <input
                            className='w-100 pa3 mv2'
                            value={this.state.amount}
                            placeholder='Amount'
                            onChange={(e) => this.setState({amount: e.target.value})}
                            />
                            <button className='pa3 bg-black-10 bn dim ttu pointer' onClick={() => this._handleHour(props.viewer.id)}>Add</button>
                        </div>
                        </div>
                    )
                    }
                    return <div>Loading</div>
                }}
        />
        )
  }
  _handleHour = (viewerId) => {
    const {description, amount, projectId} = this.state
    console.log(this.state)
    CreateHourMutation(description, parseInt(amount), projectId, viewerId, () => this.setState({submitted:true}))
  }
}
export default withRouter(CreateHour)

0 ответов

Другие вопросы по тегам