Ошибка 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} </span>
<span>{this.props.hour.amount} 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)