如何使用 react、redux 和 graphql 解决“未定义的 proptype”错误
Posted
技术标签:
【中文标题】如何使用 react、redux 和 graphql 解决“未定义的 proptype”错误【英文标题】:How to resolve a 'undefined proptype' error with react, redux and graphql 【发布时间】:2020-11-26 07:36:35 【问题描述】:我正在尝试学习如何使用 graphql 构建 React/Redux 应用程序,但在解决“未捕获的类型错误:无法读取未定义的属性“记录”错误时遇到问题。
当我尝试使用“match.params.recordId”从 url (.../record/:recordId) 中提取“记录”ID 并将其发送到操作/reducer 方法时,我遇到了这个错误.
我的代码包含 console.log 语句来尝试跟踪组件、操作和 reducer 之间的“记录”道具的值,但是从不调用日志。这让我相信组件从不使用“useEffect”挂钩来调用操作,但我不确定。
我的记录组件:
import React, useState, useEffect from 'react'
import connect from 'react-redux';
import PropTypes from 'prop-types';
import getrecord from '../../actions/records';
import Container, Row, Col, Card, Button, Form, ListGroup, Jumbotron, Modal from 'react-bootstrap';
const MyRecord = (getrecord, match, recordID = id: match.params.recordId, thisRecord:record, loading) =>
useEffect(() =>
getrecord(recordID);
, [getrecord, recordID]);
const LogInfo = () =>
console.log('record ID: ',match.params.id);
console.log('record: ', record);
LogInfo();
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<>
record === null ? (
<h2>Loading...</h2>
) : (
<Container id='MyRecord'>
<Row>
<Jumbotron className='recordJumbotron'>
<h1>Record: record.recordname </h1>
<Row>
<Col>
<Button variant="primary" onClick=handleShow>
Add an Item To Your Record
</Button>
<Modal show=show onHide=handleClose>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email" placeholder="Enter email" />
<Form.Text className="text-muted">
We'll never share your email with anyone else.
</Form.Text>
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" placeholder="Password" />
</Form.Group>
<Form.Group controlId="formBasicCheckbox">
<Form.Check type="checkbox" label="Check me out" />
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick=handleClose>
Close
</Button>
<Button variant="primary" onClick=handleClose>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</Col>
<Col>
<Button>Upload a Document</Button>
</Col>
</Row>
</Jumbotron>
</Row>
<Row className='recordItemList'>
<Card className='recordItemList'>
<Card.Header>Record Items</Card.Header>
<Card.Body>
<Card.Title>Special title treatment</Card.Title>
<ListGroup variant="flush">
<ListGroup.Item>Cras justo odio</ListGroup.Item>
<ListGroup.Item>Dapibus ac facilisis in</ListGroup.Item>
<ListGroup.Item>Morbi leo risus</ListGroup.Item>
<ListGroup.Item>Porta ac consectetur ac</ListGroup.Item>
</ListGroup>
</Card.Body>
</Card>
</Row>
</Container>
)
</>
)
MyRecord.propTypes =
getrecord: PropTypes.func.isRequired,
thisRecord: PropTypes.object
;
const mapStateToProps = state => (
thisRecord: state.record
);
export default connect(mapStateToProps, getrecord)(MyRecord)
Records Reducer 文件:
import
CREATE_RECORD_SUCCESS,
CREATE_RECORD_FAIL,
LIST_RECORDS_BY_OWNER,
GET_RECORD_BY_OWNER,
GET_RECORDS_SUBSCRIPTION
from '../actions/types';
const initialState =
record: null,
records: [],
loading: true,
error:
;
export default function (state = initialState, action)
const type, payload = action;
switch(type)
case CREATE_RECORD_SUCCESS:
return
...state,
...payload,
//record:[payload, ...state.records],
loading: false
;
case GET_RECORD_BY_OWNER:
return
...state,
record: payload,
loading: false
;
case LIST_RECORDS_BY_OWNER:
return
...state,
records:payload,
loading: false
;
case GET_RECORDS_SUBSCRIPTION:
return
...state,
records:[payload, ...state.records],
loading: false
;
case CREATE_RECORD_FAIL:
return
...state,
error: payload,
loading: false
;
default:
return state;
记录操作:
//GET A RECORD
//GET A RECORD
export const getrecord = (recordID) => async dispatch =>
try
console.log(' id: ', recordID);
const res = await API.graphql(graphqlOperation(getRecord, recordID))
console.log('record by id: ', res.data.getRecord);
dispatch(
type: GET_RECORD_BY_OWNER,
payload: res.data.getRecord
)
console.log('getrecord: ', res)
catch (error)
console.error(error);
dispatch(
type: CREATE_RECORD_FAIL
);
【问题讨论】:
【参考方案1】:您对 Proptype 的导入有误。这将是
import PropTypes from 'prop-types';
验证将是:
MyRecord.propTypes =
getrecord: PropTypes.func.isRequired,
thisRecord: PropTypes.object
;
【讨论】:
感谢您发现错字,代码已更新。不幸的是,这对 undefined 属性没有帮助......【参考方案2】:使用对象操作链时尝试验证
使用前检查未定义
match?.params?.recordId
这样可以防止出错。
【讨论】:
【参考方案3】:答案:问题实际上出在我的组件中。我的 mapStateToProps 方法有错字“...state.record”,但由于操作集名称应该是“...state.records”。这就是为什么“记录”未定义并且操作/记录方法甚至从未被调用的原因。
【讨论】:
以上是关于如何使用 react、redux 和 graphql 解决“未定义的 proptype”错误的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 react、redux 和 graphql 解决“未定义的 proptype”错误
如何组织 Redux Action-Creators 以在 Redux-React 中使用
如何使用来自 react-redux-firebase 的 redux thunk getFireBase 和 getFirestore 将数据添加到 firebase doc
如何使用 thunk 和 useDispatch(react-redux 挂钩)从操作中返回承诺?