iT邦幫忙

0

React老問題,setState後畫面沒有立即Render,但這次不能用useEffect ><

  • 分享至 

  • xImage

程式目的是這樣的,我的規格類型select選單選完後,旁邊的規格名稱會對應出資料庫裡該類型裡面已經設定好的名稱(ex. 我選溫度,旁邊的規格名稱select就會有100, 60, 等可以選,選擇單位,就會有杯、碗 等可以選)。
現在遇到狀況一樣式規格select選擇了,程式碼是有跑setState了,但是旁邊的名稱select選單沒有render所以看到的選項還是上一次選擇的內容。
https://ithelp.ithome.com.tw/upload/images/20210706/201365849LDfmXFZ2f.png
程式碼如下:

  1. 規格類型的select
<Select
  value={type}
  onChange={handleChangeSelect} >
  <MenuItem value="">
  <em>None</em>
  </MenuItem>
  <MenuItem value={'1'}>單位</MenuItem>
  <MenuItem value={'2'}>溫度</MenuItem>
  <MenuItem value={'3'}>糖分</MenuItem>
  <MenuItem value={'4'}>加料</MenuItem>
</Select>
  1. 點選後的handleChangeSelect function
const handleChangeSelect = (event) => {
    setType(event.target.value);
    fetchSpecification(type); //這個type就是上面那行set的那個
  };

fetchSpecification(type)的定義方式

async function fetchSpecification(type) {
    let config = {
      headers: {
        'Content-Type': "application/json",
      }
    } //config
    try{
      const response = await Axios.post(SPECIFICATION_URL, 
      { specificType: type }, config);
      setSpecList(response.data.data); //這裡data回傳是一個包很多物件的陣列
    }catch(e){
      console.log("抓取錯誤:" + e);
    }
  }

4.第二欄規格名稱的select用的specList定義

const [specList, setSpecList] = useState([]); 
//預設值一個空陣列,上面回傳的直接用set蓋掉

5.規格名稱的select

  {specList.map((s) => (
  <MenuItem value={s.specificType}>{s.specificName}</MenuItem>
  ))}

這個問題真的爬了很久的文,國內國外都有,但很多都是解釋setState為什麼不立即刷新的原理,沒有講一個正確或立即的方法(該不會React沒有吧....),大多講的是用useEffect監控某個值改變就去刷新,但那個刷新還是要重抓一次全部頁面的資料,好像都沒有一個正規的方式就是“我要的很簡單,setState完值就立即對對應的DOM節點刷新”這樣....

(Vue好像有個雙向綁定可以達成,但我不喜歡Vue的code排列方式XD....

還懇請大佬們指點一下你們遇到此問題的解決方式,感激不盡!!

看更多先前的討論...收起先前的討論...
咖咖拉 iT邦好手 1 級 ‧ 2021-07-06 15:10:39 檢舉
給你參考
https://ithelp.ithome.com.tw/articles/10236286
Logan iT邦新手 5 級 ‧ 2021-07-06 16:22:35 檢舉
感謝大大的分享,這個方式蠻不錯的,有試了一下,不過好像不適用現在遇到的這個狀況><
Logan iT邦新手 5 級 ‧ 2021-07-06 17:07:37 檢舉
對了,我想補充一下我這個畫面是按按鈕彈出的Dialog畫面,會跟這個頁面在Dialog裡面有關嗎?
DanSnow iT邦好手 1 級 ‧ 2021-07-06 20:03:46 檢舉
你直接在 event handler 裡呼叫 fetchSpecification ?那很簡單啊,你的 event.target.value 就是你新的 type ,直接把這個東西傳進 fetchSpecification 就好了啊,你也知道用 type 因為不會馬上更新而用到舊的值,那你就自己直接把新的值傳進去不就行了?
Logan iT邦新手 5 級 ‧ 2021-07-07 14:43:47 檢舉
XD 對吼 直接傳 event.target.value 就好了,完全沒想到,感謝大大
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
1
harry xie
iT邦研究生 1 級 ‧ 2021-07-06 15:07:30

這個問題我也有碰過,也看過很多說法像是 useState 是非同步的
然後還有看到文章寫說跟 queue 有關,某些事情執行完才會更新 state 的值
還有 closure 有關的@@,忘記哪裡看到的

我後來是用這個套件解決,你可以用看看
https://github.com/Aminadav/react-useStateRef#readme

Logan iT邦新手 5 級 ‧ 2021-07-06 16:27:21 檢舉

感謝大大,這個感覺好厲害,而且作者直接說他也是看到好多人在問這個問題所以做這個hook給大家用XD

iT邦新手 1 級 ‧ 2021-07-19 12:02:50 檢舉

補充一下:官方文件

0
咖咖拉
iT邦好手 1 級 ‧ 2021-07-06 16:14:06

Select 取值是從 Select 而不是從MenuItem
MenuItem上的value會是傳輸的值

Logan iT邦新手 5 級 ‧ 2021-07-06 16:31:10 檢舉

嗯嗯!感謝大大,我那裡是要做傳輸值沒錯,目前call的function都沒問題,就只有規格名稱那裡因為是用specList這個陣列的狀態去map出來的選項,但是因為React setState後他不會立即render所以我的specList一直都是前一次的狀態。

咖咖拉 iT邦好手 1 級 ‧ 2021-07-06 22:09:56 檢舉

https://codesandbox.io/s/dank-sun-9mebv?file=/src/App4.js
用Select 帶值到Axios在map 到畫面 是沒問題的
用useEffect的話/images/emoticon/emoticon06.gif

Logan iT邦新手 5 級 ‧ 2021-07-07 14:45:42 檢舉

感謝大大的範例,原來是這樣!!

0
Todd
iT邦新手 1 級 ‧ 2021-07-06 16:30:19

不懂為什麼這樣不能用useEffect
怕useEffect的影響的層級太大
不就specSelect另外切成一個component
在裡面useEffect dependencies放從prop來的type就好

Logan iT邦新手 5 級 ‧ 2021-07-07 14:48:14 檢舉

喔喔!好呦!因為目前還在開發狀態,想說東西都先寫一起,因為子元件有用useEffect了,怕畫面載入渲染太多次所以想說這裡先不用試試,不過之後應該會照大大講的拆分component

0
Han
iT邦研究生 1 級 ‧ 2021-07-07 10:21:47
Logan iT邦新手 5 級 ‧ 2021-07-07 14:52:22 檢舉

瞭解了!感謝大大,原來我之前一直執著在點擊select的change事件觸發抓取資料,原來把抓取資料的function直接放useEffect就可以了><

我要發表回答

立即登入回答