最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React hooks異步操作踩坑記錄

 更新時(shí)間:2024年03月13日 09:35:10   作者:代碼搬運(yùn)工_田先森  
這篇文章主要介紹了React hooks異步操作踩坑記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

useEffect 和異步任務(wù)搭配使用的時(shí)候會(huì)遇到的一些坑總結(jié)。

三個(gè)常見(jiàn)的問(wèn)題:

? 1、如何在組件加載的時(shí)候發(fā)起異步任務(wù)

? 2、如何在組件交互的時(shí)候發(fā)起異步任務(wù)

? 3、其他陷阱

一、react hooks發(fā)異步請(qǐng)求

1、使用useEffect發(fā)起異步任務(wù),第二個(gè)參數(shù)使用空數(shù)組可以實(shí)現(xiàn)組件加載的時(shí)候執(zhí)行方法體,返回值函數(shù)在組件卸載時(shí)執(zhí)行一次,用來(lái)清理一些東西。

2、使用 AbortController 或者某些庫(kù)自帶的信號(hào)量 ( axios.CancelToken) 來(lái)控制中止請(qǐng)求,更加優(yōu)雅地退出

3、當(dāng)需要在其他地方(例如點(diǎn)擊處理函數(shù)中)設(shè)定定時(shí)器,在useEffect返回值中清理時(shí),使用局部變量或者useRef來(lái)記錄這個(gè)timer,不要使用useState.

4、組件中出現(xiàn)setTimeout等閉包時(shí),盡量在閉包內(nèi)部引用ref而不是state,否則容易出現(xiàn)讀取到舊的值

5、useState返回的更新?tīng)顟B(tài)方法是異步的,要在下次重繪的時(shí)候才能獲取新的值。不要試圖在更改狀態(tài)之后立馬獲取狀態(tài)。

二、如何在組件加載的時(shí)候發(fā)起異步任務(wù)

這類(lèi)需求非常常見(jiàn),典型的例子是在列表組件加載的時(shí)候發(fā)送請(qǐng)求到后端,獲取列表展現(xiàn)。

import React, { useState, useEffect } from 'react';
  const SOME_API = '/api/get/value';
  export const MyComponent: React.FC<{}> = => {
  const [loading, setLoading] = useState(true);
  const [value, setValue] = useState(0);
  useEffect( => {
    (async => {
      const res = await fetch(SOME_API);
      const data = await res.json;
      setValue(data.value);
      setLoading(false);
    });
  }, []);
  return (
    <>
      {
        loading ? (
        <h2>Loading...</h2>
        ) : (
        <h2>value is {value}</h2>
        )
      }
    </>
  );
}

如上是一個(gè)基礎(chǔ)的帶 Loading 功能的組件,會(huì)發(fā)送異步請(qǐng)求到后端獲取一個(gè)值并顯示到頁(yè)面上。

如果以示例的標(biāo)準(zhǔn)來(lái)說(shuō)已經(jīng)足夠,但要實(shí)際運(yùn)用到項(xiàng)目中,還不得不考慮幾個(gè)問(wèn)題

三、如果在響應(yīng)回來(lái)之前組件被銷(xiāo)毀了會(huì)怎樣?

這時(shí)候React會(huì)報(bào)一個(gè)??警告信息:

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subions and asynchronous tasks in a useEffect cleanup http://function.in Notification

就是說(shuō)一個(gè)組件卸載之后不應(yīng)該再修改他的狀態(tài)。雖然不影響運(yùn)行,但是這種問(wèn)題不應(yīng)該存在。那么如何解決?

問(wèn)題的核心在于,在組件卸載后依然調(diào)用了 setValue(data.value)和 setLoading(false)來(lái)更改狀態(tài)。

因此一個(gè)簡(jiǎn)單的辦法是標(biāo)記一下組件有沒(méi)有被卸載,可以利用 useEffect的返回值。

// 省略組件其他內(nèi)容,只列出 diff
useEffect( => {
  let isUnmounted = false;
  (async => {
    const res = await fetch(SOME_API);
    const data = await res.json;
    if (!isUnmounted) {
      setValue(data.value);
      setLoading(false);
    }
  });
  return => {
  isUnmounted = true;
  }
}, []);

這樣可以順利避免這個(gè) Warning。

有沒(méi)有更加優(yōu)雅的解法?

上述做法是在收到響應(yīng)時(shí)進(jìn)行判斷,即無(wú)論如何需要等響應(yīng)完成,略顯被動(dòng)。

一個(gè)更加主動(dòng)的方式是探知到卸載時(shí)直接中斷請(qǐng)求,自然也不必再等待響應(yīng)了。

這種主動(dòng)方案需要用到 AbortController。

AbortController 是一個(gè)瀏覽器的實(shí)驗(yàn)接口,它可以返回一個(gè)信號(hào)量(singal),從而中止發(fā)送的請(qǐng)求。

這個(gè)接口的兼容性不錯(cuò),除了 IE 之外全都兼容(如 Chrome, Edge, FF 和絕大部分移動(dòng)瀏覽器,包括 Safari)。

useEffect( => {
  let isUnmounted = false;
  const abortController = new AbortController; // 創(chuàng)建
  (async => {
    const res = await fetch(SOME_API, {
    singal: abortController.singal, // 當(dāng)做信號(hào)量傳入
    });
    const data = await res.json;
    if (!isUnmounted) {
      setValue(data.value);
      setLoading(false);
    }
  });
  return => {
    isUnmounted = true;
    abortController.abort; // 在組件卸載時(shí)中斷
  }
}, []);

singal 的實(shí)現(xiàn)依賴(lài)于實(shí)際發(fā)送請(qǐng)求使用的方法,如上述例子的 fetch方法接受 singal屬性。

如果使用的是 axios,它的內(nèi)部已經(jīng)包含了 axios.CancelToken,可以直接使用,例子在這里。

import React, { Component } from 'react';
import axios from 'axios';

class Example extends Component {
  signal = axios.CancelToken.source();

  state = {
    isLoading: false,
    user: {},
  }
  
  componentDidMount() {
    this.onLoadUser();
  }
  
  componentWillUnmount() {
    this.signal.cancel('Api is being canceled');
  }
  
  onLoadUser = async () => {
    try {
      this.setState({ isLoading: true });
      const response = await axios.get('https://randomuser.me/api/', {
        cancelToken: this.signal.token,
      })
      this.setState({ user: response.data, isLoading: true });
    } catch (err) {
      if (axios.isCancel(err)) {
        console.log('Error: ', err.message); // => prints: Api is being canceled
      } else {
        this.setState({ isLoading: false });
      }
    }
   } 
    render() {
      return (
        <div>
          <pre>{JSON.stringify(this.state.user, null, 2)}</pre>
        </div>
      )
    }
 
}

四、如何在組件交互時(shí)發(fā)起異步任務(wù)

? 另一種常見(jiàn)的需求是要在組件交互(比如點(diǎn)擊某個(gè)按鈕)時(shí)發(fā)送請(qǐng)求或者開(kāi)啟計(jì)時(shí)器,待收到響應(yīng)后修改數(shù)據(jù)進(jìn)而影響頁(yè)面

這里和上面一節(jié)(組件加載時(shí))最大的差異在于 React Hooks 只能在組件級(jí)別編寫(xiě),不能在方法(dealClick)或者控制邏輯(if, for 等)內(nèi)部編寫(xiě),所以不能在點(diǎn)擊的響應(yīng)函數(shù)中再去調(diào)用 useEffect。但我們依然要利用 useEffect 的返回函數(shù)來(lái)做清理工作。

? 以計(jì)時(shí)器為例,假設(shè)我們想做一個(gè)組件,點(diǎn)擊按鈕后開(kāi)啟一個(gè)計(jì)時(shí)器(5s),計(jì)時(shí)器結(jié)束后修改狀態(tài)。

但如果在計(jì)時(shí)未到就銷(xiāo)毀組件時(shí),我們想停止這個(gè)計(jì)時(shí)器,避免內(nèi)存泄露。用代碼實(shí)現(xiàn)的話(huà),會(huì)發(fā)現(xiàn)開(kāi)啟計(jì)時(shí)器和清理計(jì)時(shí)器會(huì)在不同的地方,因此就必須記錄這個(gè) timer。

看如下的例子:

import React, { useState, useEffect } from 'react';
 
export const MyComponent: React.FC<{}> = () => {
    const [value, setValue] = useState(0);
 
    let timer: number;
 
    useEffect(() => {
        // timer 需要在點(diǎn)擊時(shí)建立,因此這里只做清理使用
        return () => {
            console.log('in useEffect return', timer); // <- 正確的值
            window.clearTimeout(timer);
        }
    }, []);
 
    function dealClick() {
        timer = window.setTimeout(() => {
            setValue(100);
        }, 5000);
    }
 
    return (
        <>
            <span>Value is {value}</span>
            <button onClick={dealClick}>Click Me!</button>
        </>
    );
}

既然要記錄 timer,自然是用一個(gè)內(nèi)部變量來(lái)存儲(chǔ)即可(暫不考慮連續(xù)點(diǎn)擊按鈕導(dǎo)致多個(gè) timer 出現(xiàn),假設(shè)只點(diǎn)一次。因?yàn)閷?shí)際情況下點(diǎn)了按鈕還會(huì)觸發(fā)其他狀態(tài)變化,繼而界面變化,也就點(diǎn)不到了)。

這里需要注意的是,如果把 timer 升級(jí)為狀態(tài)(state),則代碼反而會(huì)出現(xiàn)問(wèn)題。

考慮如下代碼:

import React, { useState, useEffect } from 'react';
 
export const MyComponent: React.FC<{}> = () => {
    const [value, setValue] = useState(0);
    const [timer, setTimer] = useState(0); // 把 timer 升級(jí)為狀態(tài)
 
    useEffect(() => {
        // timer 需要在點(diǎn)擊時(shí)建立,因此這里只做清理使用
        return () => {
            console.log('in useEffect return', timer); // <- 0
            window.clearTimeout(timer);
        }
    }, []);
 
    function dealClick() {
        let tmp = window.setTimeout(() => {
            setValue(100);
        }, 5000);
        setTimer(tmp);
    }
 
    return (
        <>
            <span>Value is {value}</span>
            <button onClick={dealClick}>Click Me!</button>
        </>
    );
}

有關(guān)語(yǔ)義上 timer 到底算不算作組件的狀態(tài)我們先拋開(kāi)不談,僅就代碼層面來(lái)看。

利用 useState 來(lái)記住 timer 狀態(tài),利用 setTimer 去更改狀態(tài),看似合理。

但實(shí)際運(yùn)行下來(lái),在 useEffect 返回的清理函數(shù)中,得到的 timer 卻是初始值,即 0。

為什么兩種寫(xiě)法會(huì)有差異呢?

其核心在于寫(xiě)入的變量和讀取的變量是否是同一個(gè)變量。

第一種寫(xiě)法: 代碼是把 timer 作為組件內(nèi)的局部變量使用。在初次渲染組件時(shí),useEffect 返回的閉包函數(shù)中指向了這個(gè)局部變量 timer。在 dealClick 中設(shè)置計(jì)時(shí)器時(shí)返回值依舊寫(xiě)給了這個(gè)局部變量(即讀和寫(xiě)都是同一個(gè)變量),因此在后續(xù)卸載時(shí),雖然組件重新運(yùn)行導(dǎo)致出現(xiàn)一個(gè)新的局部變量 timer,但這不影響閉包內(nèi)老的 timer,所以結(jié)果是正確的。

第二種寫(xiě)法: timer 是一個(gè) useState 的返回值,并不是一個(gè)簡(jiǎn)單的變量。從 React Hooks 的源碼來(lái)看,它返回的是 [hook.memorizedState, dispatch],對(duì)應(yīng)我們接的值和變更方法。當(dāng)調(diào)用 setTimersetValue 時(shí),分別觸發(fā)兩次重繪,使得 hook.memorizedState 指向了 newState(注意:不是修改,而是重新指向)。但 useEffect 返回閉包中的 timer 依然指向舊的狀態(tài),從而得不到新的值。(即讀的是舊值,但寫(xiě)的是新值,不是同一個(gè))

? 如果覺(jué)得閱讀 Hooks 源碼有困難,可以從另一個(gè)角度去理解:雖然 React 在 16.8 推出了 Hooks,但實(shí)際上只是加強(qiáng)了函數(shù)式組件的寫(xiě)法,使之擁有狀態(tài),用來(lái)作為類(lèi)組件的一種替代,但 React 狀態(tài)的內(nèi)部機(jī)制沒(méi)有變化。在 React 中 setState 內(nèi)部是通過(guò) merge 操作將新?tīng)顟B(tài)和老狀態(tài)合并后,重新返回一個(gè)新的狀態(tài)對(duì)象。不論 Hooks 寫(xiě)法如何,這條原理沒(méi)有變化。現(xiàn)在閉包內(nèi)指向了舊的狀態(tài)對(duì)象,而 setTimersetValue 重新生成并指向了新的狀態(tài)對(duì)象,并不影響閉包,導(dǎo)致了閉包讀不到新的狀態(tài)。

我們注意到 React 還提供給我們一個(gè) useRef, 它的定義是:

  • useRef 返回一個(gè)可變的 ref 對(duì)象,其 current 屬性被初始化為傳入的參數(shù)(initialValue)。
  • 返回的 ref 對(duì)象在組件的整個(gè)生命周期內(nèi)保持不變。

ref 對(duì)象可以確保在整個(gè)生命周期中值不變,且同步更新,是因?yàn)?ref 的返回值始終只有一個(gè)實(shí)例,所有讀寫(xiě)都指向它自己。所以也可以用來(lái)解決這里的問(wèn)題。

import React, { useState, useEffect, useRef } from 'react';
 
export const MyComponent: React.FC<{}> = () => {
    const [value, setValue] = useState(0);
    const timer = useRef(0);
 
    useEffect(() => {
        // timer 需要在點(diǎn)擊時(shí)建立,因此這里只做清理使用
        return () => {
            window.clearTimeout(timer.current);
        }
    }, []);
 
    function dealClick() {
        timer.current = window.setTimeout(() => {
            setValue(100);
        }, 5000);
    }
 
    return (
        <>
            <span>Value is {value}</span>
            <button onClick={dealClick}>Click Me!</button>
        </>
    );
}

事實(shí)上我們后面會(huì)看到,useRef 和異步任務(wù)配合更加安全穩(wěn)妥。

五、其他陷阱

修改狀態(tài)是異步的

//錯(cuò)誤例子
import React, { useState } from 'react';
 
export const MyComponent: React.FC<{}> = () => {
    const [value, setValue] = useState(0);
 
    function dealClick() {
        setValue(100);
        console.log(value); // <- 0
    }
 
    return (
        <span>Value is {value}, AnotherValue is {anotherValue}</span>
    );
}

useState 返回的修改函數(shù)是異步的,調(diào)用后并不會(huì)直接生效,因此立馬讀取 value 獲取到的是舊值(0)。

React 這樣設(shè)計(jì)的目的是為了性能考慮,爭(zhēng)取把所有狀態(tài)改變后只重繪一次就能解決更新問(wèn)題,而不是改一次重繪一次,也是很容易理解的。

在 timeout 中讀不到其他狀態(tài)的新值

//錯(cuò)誤例子
import React, { useState, useEffect } from 'react';
 
export const MyComponent: React.FC<{}> = () => {
    const [value, setValue] = useState(0);
    const [anotherValue, setAnotherValue] = useState(0);
 
    useEffect(() => {
        window.setTimeout(() => {
            console.log('setAnotherValue', value) // <- 0
            setAnotherValue(value);
        }, 1000);
        setValue(100);
    }, []);
 
    return (
        <span>Value is {value}, AnotherValue is {anotherValue}</span>
    );
}

這個(gè)問(wèn)題和上面使用 useState 去記錄 timer 類(lèi)似,在生成 timeout 閉包時(shí),value 的值是 0。

雖然之后通過(guò) setValue 修改了狀態(tài),但 React 內(nèi)部已經(jīng)指向了新的變量,而舊的變量仍被閉包引用,所以閉包拿到的依然是舊的初始值,也就是 0。

要修正這個(gè)問(wèn)題,也依然是使用 useRef,如下:

import React, { useState, useEffect, useRef } from 'react';
 
export const MyComponent: React.FC<{}> = () => {
    const [value, setValue] = useState(0);
    const [anotherValue, setAnotherValue] = useState(0);
    const valueRef = useRef(value);
    valueRef.current = value;
 
    useEffect(() => {
        window.setTimeout(() => {
            console.log('setAnotherValue', valueRef.current) // <- 100
            setAnotherValue(valueRef.current);
        }, 1000);
        setValue(100);
    }, []);
 
    return (
        <span>Value is {value}, AnotherValue is {anotherValue}</span>
    );
}

還是 timeout 的問(wèn)題

假設(shè)我們要實(shí)現(xiàn)一個(gè)按鈕,默認(rèn)顯示 false。當(dāng)點(diǎn)擊后更改為 true,但兩秒后變回 false( true 和 false 可以互換)。

考慮如下代碼:

import React, { useState } from 'react';
 
export const MyComponent: React.FC<{}> = () => {
    const [flag, setFlag] = useState(false);
 
    function dealClick() {
        setFlag(!flag);
 
        setTimeout(() => {
            setFlag(!flag);
        }, 2000);
    }
 
    return (
        <button onClick={dealClick}>{flag ? "true" : "false"}</button>
    );
}

我們會(huì)發(fā)現(xiàn)點(diǎn)擊時(shí)能夠正常切換,但是兩秒后并不會(huì)變回來(lái)。

究其原因,依然在于 useState 的更新是重新指向新值,但 timeout 的閉包依然指向了舊值。

所以在例子中,flag 一直是 false,雖然后續(xù) setFlag(!flag),但依然沒(méi)有影響到 timeout 里面的 flag。

解決方法有二。

第一個(gè)還是利用 useRef

import React, { useState, useRef } from 'react';
 
export const MyComponent: React.FC<{}> = () => {
    const [flag, setFlag] = useState(false);
    const flagRef = useRef(flag);
    flagRef.current = flag;
 
    function dealClick() {
        setFlag(!flagRef.current);
 
        setTimeout(() => {
            setFlag(!flagRef.current);
        }, 2000);
    }
 
    return (
        <button onClick={dealClick}>{flag ? "true" : "false"}</button>
    );
}

第二個(gè)是利用 setFlag 可以接收函數(shù)作為參數(shù),并利用閉包和參數(shù)來(lái)實(shí)現(xiàn)(函數(shù)式更新)

import React, { useState } from 'react';
 
export const MyComponent: React.FC<{}> = () => {
    const [flag, setFlag] = useState(false);
 
    function dealClick() {
        setFlag(!flag);
 
        setTimeout(() => {
            setFlag(flag => !flag);
        }, 2000);
    }
 
    return (
        <button onClick={dealClick}>{flag ? "true" : "false"}</button>
    );
}

當(dāng) setFlag 參數(shù)為函數(shù)類(lèi)型時(shí),這個(gè)函數(shù)的意義是告訴 React 如何從當(dāng)前狀態(tài)產(chǎn)生出新的狀態(tài)(類(lèi)似于 redux 的 reducer,不過(guò)是只針對(duì)一個(gè)狀態(tài)的子 reducer)。既然是當(dāng)前狀態(tài),因此返回值取反,就能夠?qū)崿F(xiàn)效果。

總結(jié)

? 在 Hook 中出現(xiàn)異步任務(wù)尤其是 timeout 的時(shí)候,我們要格外注意。

useState 只能保證多次重繪之間的狀態(tài)是一樣的,但不保證它們就是同一個(gè)對(duì)象,因此出現(xiàn)閉包引用的時(shí)候,盡量使用 useRef 而不是直接使用 state 本身,否則就容易踩坑。

反之如果的確碰到了設(shè)置了新值但讀取到舊值的情況,也可以往這個(gè)方向想想,可能就是這個(gè)原因所致。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • React大文件分片上傳原理及方案

    React大文件分片上傳原理及方案

    前端進(jìn)行大文件分片上傳的方案幾乎都是利用Blob.prototype.slice方法對(duì)文件進(jìn)行分片,用數(shù)組將每一個(gè)分片存起來(lái),最后將分片發(fā)給后端,本文給大家介紹React大文件分片上傳方案,感興趣的朋友跟隨小編一起看看吧
    2023-08-08
  • React?Hooks中?useRef和useImperativeHandle的使用方式

    React?Hooks中?useRef和useImperativeHandle的使用方式

    這篇文章主要介紹了React?Hooks中?useRef和useImperativeHandle的使用方式,文中說(shuō)明了useRef和useCallback一起使用,?可以解決閉包陷阱的問(wèn)題,本文結(jié)合實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-10-10
  • windows下create-react-app 升級(jí)至3.3.1版本踩坑記

    windows下create-react-app 升級(jí)至3.3.1版本踩坑記

    這篇文章主要介紹了windows下create-react-app 升級(jí)至3.3.1版本踩坑記,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • react build 后打包發(fā)布總結(jié)

    react build 后打包發(fā)布總結(jié)

    這篇文章主要介紹了react build 后打包發(fā)布總結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • React 并發(fā)功能體驗(yàn)(前端的并發(fā)模式)

    React 并發(fā)功能體驗(yàn)(前端的并發(fā)模式)

    React 是由 Facebook 軟件工程師 Jordan Walke 創(chuàng)建,React 的第一個(gè)版本在七年前問(wèn)世,現(xiàn)在,F(xiàn)acebook 負(fù)責(zé)維護(hù),本文給大家介紹React 并發(fā)功能體驗(yàn)前端并發(fā)模式的問(wèn)題,感興趣的朋友跟隨小編一起看看吧
    2021-07-07
  • 在React項(xiàng)目中使用iframe嵌入一個(gè)網(wǎng)站的步驟

    在React項(xiàng)目中使用iframe嵌入一個(gè)網(wǎng)站的步驟

    本文介紹了如何在React項(xiàng)目中通過(guò)iframe嵌入百度網(wǎng)站的步驟,首先創(chuàng)建一個(gè)Baidu.js組件,并在該組件中設(shè)置iframe來(lái)加載百度,然后在A(yíng)pp.js中引入并使用Baidu組件,還討論了因安全策略可能無(wú)法加載某些網(wǎng)站的問(wèn)題,需要的朋友可以參考下
    2024-09-09
  • react之組件通信詳解

    react之組件通信詳解

    本篇文章主要介紹了React組件通信詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2021-10-10
  • 詳解react應(yīng)用中的DOM DIFF算法

    詳解react應(yīng)用中的DOM DIFF算法

    這篇文章主要介紹了react應(yīng)用中的DOM DIFF算法,幫助大家更好的理解和學(xué)習(xí)使用react,感興趣的朋友可以了解下
    2021-04-04
  • React的三大屬性你都知道嗎

    React的三大屬性你都知道嗎

    這篇文章主要為大家詳細(xì)介紹了React的三大屬性,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-02-02
  • React事件綁定的方式詳解

    React事件綁定的方式詳解

    react事件綁定時(shí)。this并不會(huì)指向當(dāng)前DOM元素。往往使用bind來(lái)改變this指向,今天通過(guò)本文給大家介紹React事件綁定的方式,感興趣的朋友
    2021-07-07

最新評(píng)論

秦皇岛市| 伊通| 启东市| 澜沧| 平安县| 阿拉善左旗| 上思县| 平顺县| 长治县| 英吉沙县| 侯马市| 江城| 灵山县| 漠河县| 方山县| 宜良县| 南丹县| 东源县| 临湘市| 静安区| 江川县| 临海市| 民乐县| 惠安县| 北川| 吴堡县| 含山县| 兰州市| 灌云县| 板桥市| 高淳县| 永仁县| 如皋市| 蕉岭县| 南乐县| 思南县| 兴隆县| 沙洋县| 义乌市| 湘乡市| 眉山市|