記錄一下這陣子寫react時(shí) Apollo踩下的坑
背景: 項(xiàng)目使用 creat-react-app 搭建腳手架, 技術(shù)棧GraphQL+Apollo+React 爽蝴,所以下面這幾個(gè)包少不了
apollo-boost
: Package containing everything you need to set up Apollo Clientreact-apollo
: View layer integration for Reactgraphql-tag
: Necessary for parsing your GraphQL queriesgraphql
: Also parses your GraphQL queries
說明白了 GraphQL 和數(shù)據(jù)庫本身并沒有直接關(guān)系鸯隅,但相當(dāng)于平時(shí)寫的 Get Post請求
這里主要用 react-apollo 的兩個(gè)核心組件: Query
Mutation
Query
坑
Apollo 的<Query></Query> 查詢組件只能在render() 里面執(zhí)行巨朦,而在react中 render() 顧名思義--渲染 是不能修改組件的state 也就是說 setState是用不了了,那么我有個(gè)問題 如果獲取數(shù)據(jù)之后赶撰,傳入子組件那么
1. 子組件的操作 如何修改狀態(tài)?
2. 子組件修改狀態(tài)之后舌镶,父組件如何刷新數(shù)據(jù)?
const IMAGE_ORDER_LIST = gql`
query OrderListQuery($status:Int, $page: Int, $priceSort: String, $keyword: String, $time: String) {
OrderListQuery(status: $status, page: $page ,priceSort: $priceSort, keyword: $keyword, time: $time) {
items {
order_num
id
price
image_url
status_msg
created_on
}
paginate {
current_page
last_page
}
}
}`
class Parent extends React.Component {
render() {
<Query query={IMAGE_ORDER_LIST}>
{({ loading, error, data }) => {
if (loading) return //do something
if (error) return //do something
return (
<div>
<ChildA orders={data.xx} ></ChildA>
<ChildB orders={data.aa} ></ChildB>
<ChildC orders={data.ss} ></ChildC>
</div>
)
}}
</Query>
}
}
折騰了好久,最后找到暫時(shí)解決的辦法豪娜,記錄下
問題1
問題大致還原成: 實(shí)現(xiàn) 單選 or 全選訂單餐胀,并且進(jìn)行 駁回 or 通過操作 傳送門 ->
想過的點(diǎn)
- 想過父組件傳遞函數(shù)給checkbox組件里面更改自身狀態(tài),但是更改后的狀態(tài)如何傳遞給爺爺組件.. 這就尷尬了
- 在爺瘤载、 父 否灾、子組件中,將操作邏輯放置 父組件鸣奔,但是三個(gè)組件的通訊問題 又成了問題墨技,不會要用redux吧...
后來找到例子: https://codesandbox.io/s/j4krmvw4ky 實(shí)際上是用 狀態(tài)提升方法 由此想到思路, 把 Parent 組件中的 ChildA 挎狸、 ChildB 扣汪、 ChildC 重新封裝起來成 BigChild組件,然后將Parnet 獲取到的數(shù)據(jù)傳入 BigChild轉(zhuǎn)化為state锨匆,這樣就可以更改狀態(tài)啦~
//Parent .js
class Parent extends React.Component {
render() {
<Query query={IMAGE_ORDER_LIST}>
{({ loading, error, data }) => {
if (loading) return //do something
if (error) return //do something
return (
<div>
<BigChild orders={data} ></BigChild>
</div>
)
}}
</Query>
}
}
//BigChild .js
class BigChild extends React.Component {
constructor(props) {
super(props)
this.state = {
data: this.props.orders
}
}
render() {
let { data } = this.state
return (
<div>
<ChildA orders={data} ></ChildA>
<ChildA orders={data} ></ChildA>
<ChildA orders={data} ></ChildA>
</div>
)
}
}
問題2
問題1解決了崭别,訂單操作完成之后,重新進(jìn)入Parent 頁面之后 render() 還是修改之前的數(shù)據(jù)
查了文檔,發(fā)現(xiàn)apollo是有緩存機(jī)制的
By default your component will try to read from the cache first, and if the full data for your query is in the cache then Apollo simply returns the data from the cache 【Click to read me!】
而apollo自帶兩種刷新數(shù)據(jù)方法是 pollInterval 以及 refetch
pollInterval
顧名思義 輪詢紊遵,類似setInterVal()账千, 周期可以作為參數(shù) 自定義,使用方法是 pollInterval ={ time }
//500毫秒查詢一次
<Query
query={IMAGE_ORDER_LIST}
pollInterval={500}
notifyOnNetworkStatusChange //一定要開啟暗膜,監(jiān)控狀態(tài)碼
>
{({ loading, error, data, startPolling, stopPolling }) => {
//loading error就似乎沒用了
if (networkStatus === 7) {
stopPolling() //停止輪詢
//加載完成
} else if (networkStatus < 7) {
return //loading
} else if (networkStatus === 8) {
return //出錯(cuò)
}
}}
</Query>
狀態(tài)碼:
-
loading:
該查詢從未運(yùn)行過匀奏,現(xiàn)在請求正在等待 -
setVariables:
查詢的變量發(fā)生變化 -
fetchMore:
表示fetchMore在此查詢上調(diào)用了該命令,并且創(chuàng)建的網(wǎng)絡(luò)請求當(dāng)前正在運(yùn)行 -
refetch:
這意味著refetch已在查詢中調(diào)用并且重新獲取請求當(dāng)前正在運(yùn)行学搜。 - ...略
-
poll:
表示輪詢查詢當(dāng)前正在運(yùn)行 -
ready:
加載完成 -
error:
錯(cuò)誤
refetch
這個(gè)非常實(shí)用娃善,如果在組件內(nèi)更新,或者點(diǎn)擊事件之類 更新數(shù)據(jù)瑞佩,直接參考說明文檔例子,點(diǎn)擊即可實(shí)現(xiàn)聚磺。
const DogPhoto = ({ breed }) => (
<Query
query={GET_DOG_PHOTO}
variables={{ breed }}
skip={!breed}
>
{({ loading, error, data, refetch }) => {
if (loading) return null;
if (error) return `Error!: ${error}`;
return (
<div>
<img
src={data.dog.displayImage}
style={{ height: 100, width: 100 }}
/>
<button onClick={() => refetch()}>Refetch!</button>
</div>
);
}}
</Query>
);
看上去非常實(shí)用,但是我的這個(gè)問題: 當(dāng)訂單操作完成 重新進(jìn)入parent組件頁面炬丸,再立即執(zhí)行refetch() 似乎不太可能瘫寝,如果直接添加 refetch()
{({ loading, error, data, refetch }) => {
refetch()
render (
//return something
)
}}
會發(fā)現(xiàn) 頁面一直在refetch 使用了stopPolling 也不會停止, 后來使用 訂單操作完成返回一個(gè)參數(shù)給 parent頁面稠炬,parent頁面根據(jù)參數(shù)判斷 是否進(jìn)行refetch 同樣也不行焕阿!
另外想到 添加一個(gè)隱藏button 讓頁面進(jìn)入的時(shí)候自執(zhí)行,結(jié)果頁面抽搐了...
所以只能放棄 refetch() 這個(gè)好看但用不著的方法... 難受
最后
用 pollInterval
根據(jù)狀態(tài)做了一些改善
//500毫秒查詢一次
render() {
let loadNum = 0
return (
<Query
query={IMAGE_ORDER_LIST}
pollInterval={100}
notifyOnNetworkStatusChange //一定要開啟首启,監(jiān)控狀態(tài)碼
>
{({ loading, error, data, startPolling, stopPolling }) => {
loadNum++ //輪詢時(shí)候增加
if (networkStatus === 7 && loadNum > 3) {
stopPolling() //停止輪詢
//加載完成 do something
} else if (networkStatus <= 7) {
return //loading
} else if (networkStatus === 8) {
return //出錯(cuò)
}
}}
</Query>
)
}
大功告成暮屡,還有其他的解決方法 還望大神指導(dǎo)!