首頁  >  問答  >  主體

React 報表 props."function" 不是函數

<p>我正在創建我的第一個網上商店,但遇到了問題。我製作了假 API,其中包含產品卡數據,當我使用 <code>axios.get</code> 獲取它們並添加到狀態時,我發現「props.addCardData 不是函數」。我必須說,一切工作正常,直到我添加 <code>axios.get</code> 。其他函數我使用與函數<code>addCardData</code> 相同的方式:我的意思是,我使用了<code>mapDispatchToProps</code>,我使用了<code>props.addCardData</code>,我使用了<code>props.addCardData</code> ; - 我沒有在<code>axios.get</code> 或其他請求中使用它們)。我之前使用任何功能都沒有問題。 </p> <p>我計劃透過 <code>axios.get</code> 取得數據,從卡片容器中呼叫一個函數,該函數將呼叫以操作創建者作為參數的調度。 </p> <p>我還發現「無法讀取未定義的屬性(讀取「addCardData」)。</p> <p>下面,我已經指出了受問題影響的程式碼部分(我已經指出了哪些程式碼適用於哪些元素)</p> <p>這是 Cards 元件中的程式碼(我沒有在此處新增導入,但 ofc 我擁有所有導入):</p> <pre class="brush:php;toolbar:false;">const Cards = (props) => { axios.get('https://mocki.io/v1/8cb0f160-92f7-4cf8-a6c1-f63690df514e') .then(response => { props.addCardData(response.data) }) let cardsArray = Object.keys(props.cardsData).map(card => ( <OfferCard key={card.id} bg={props.cardsData[card].bg} id={props.cardsData[card].tagId} title={props.cardsData[card].title} text={props.cardsData[card].text} button={ <Container fluid> <Row className={'row-cols-auto'}> {props.cardsData[card].button.map(button => ( ( <CardsButton key={button.id} link={button.link} type={button.type} class={button.class} name={button.name} /> ))} </Row> </Container> } /> )) return ( <Container fluid> <img src={'./backgrounds/bestoffers.png'} alt={'BEST OFFERS'} className={'img-fluid imgTab'} /> <Row xs={1} md={2} id={'cards-row'} className={'border border-4 g-3'}> {/*row-cols-* - set the cards width by setting amount of cards in row*/} {cardsArray} </Row> </Container> ) } export default Cards</pre> <p>這是 <code>CardsContainer</code> 中的程式碼:</p> <pre class="lang-js prettyprint-override"><code>const mapStateToProps = (state) => { return { cardsData: state.homePage.cardsData } } const mapDispatchToProps = (dispatch) => { return { addCardData: (data) => { dispatch(addCardsData(data)) } } } const CardsContainer = connect(mapStateToProps, mapDispatchToProps)(Cards); export default CardsContainer </code></pre> <p>這是減速機中的代碼:</p> <pre class="lang-js prettyprint-override"><code>... homePageCardsData = 'HOMEPAGE-CARDS-DATA' initialState = {...} - includes "cardsData: {}" const homePageReducer = (state = initialState, action) => { let stateCopy; switch (action.type) { case homePageCardsData: { stateCopy = {...state, cardsData: action.data} break } … default: return state; } return stateCopy; .... - some functions here (not necessary to know) } export const addCardsData = (data) => ({ type: homePageCardsData, data: data }) </code></pre> <p>當我嘗試類似的事情:</p> <pre class="lang-js prettyprint-override"><code>const addCard = props.addCardData axios.get('https://mocki.io/v1/8cb0f160-92f7-4cf8-a6c1-f63690df514e') .then(response => { addCard(response.data) }) </code></pre> <p>我在本地主機上出現延遲(在主頁上!!),所有內容都開始緩慢渲染,並且 70% 的情況下,卡片塊未渲染。在其他情況下,它可以在一段時間後渲染(很少機會)。在 AdminPanel 頁面上,我渲染 <code>Cards</code> 因為我在測試選單時需要查看更改,我收到「TypeError:addCard 不是函數。」</p> <p>如果我從組件中刪除此程式碼 - 一切都會正常。 </p> <p>我還必須說我使用了“調試器”並將其放在 <code>homePageCardsData</code> 中。腳本在偵錯器上停止(在 <code>StateCopy</code> 之後和 <code>break</code> 之前)。這意味著腳本是正確的,<code>dispatch</code> 可以工作,我可以進入案例 <code>homePageCardsData</code>。 </p>
P粉475315142P粉475315142382 天前599

全部回覆(1)我來回復

  • P粉807471604

    P粉8074716042023-09-05 09:01:34

    問題出在 Cards 元件中,它直接在元件的函數體中將 Axios GET 請求作為無意的副作用。這很可能會建立一個渲染循環,或至少在每次 Cards 渲染時發出 GET 請求。

    將此程式碼移至 useEffect 掛鉤中,以便在元件安裝後呼叫它。

    範例:

    const Cards = ({ addCardsData, cardsData }) => {
      useEffect(() => {
        axios
          .get("https://mocki.io/v1/8cb0f160-92f7-4cf8-a6c1-f63690df514e")
          .then((response) => {
            addCardsData(response.data);
          });
      }, [addCardsData]);
    
      let cardsArray = Object.keys(cardsData).map((card) => (
        <OfferCard
          key={card.id}
          bg={cardsData[card].bg}
          id={cardsData[card].tagId}
          title={cardsData[card].title}
          text={cardsData[card].text}
          button={
            <Container fluid>
              <Row className={"row-cols-auto"}>
                {cardsData[card].button.map((button) => (
                  <CardsButton
                    key={button.id}
                    link={button.link}
                    type={button.type}
                    class={button.class}
                    name={button.name}
                  />
                ))}
              </Row>
            </Container>
          }
        />
      ));
    
      return (
        ...
      );
    };
    
    const mapStateToProps = (state) => ({
      cardsData: state.homePage.cardsData
    });
    
    const mapDispatchToProps = {
      addCardsData
    };
    
    const CardsContainer = connect(mapStateToProps, mapDispatchToProps)(Cards);

    您使用的是相當舊的Redux 程式碼,我們通常不再使用connect 高階元件,因為useDispatchuseSelector 掛鉤取代了它的用法。目前的標準是使用 Redux-Toolkit確實減少了您需要編寫的樣板檔案的數量。

    以下是更新建議範例:

    import { useDispatch, useSelector } from "react-redux";
    ...
    
    const Cards = () => {
      const dispatch = useDispatch();
      const cardsData = useSelector(state => state.homePage.cardsData);
    
      useEffect(() => {
        axios
          .get("https://mocki.io/v1/8cb0f160-92f7-4cf8-a6c1-f63690df514e")
          .then((response) => {
            dispatch(addCardsData(response.data));
          });
      }, [dispatch]);
    
      let cardsArray = Object.keys(cardsData).map((card) => (
        <OfferCard
          key={card.id}
          bg={cardsData[card].bg}
          id={cardsData[card].tagId}
          title={cardsData[card].title}
          text={cardsData[card].text}
          button={
            <Container fluid>
              <Row className={"row-cols-auto"}>
                {cardsData[card].button.map((button) => (
                  <CardsButton
                    key={button.id}
                    link={button.link}
                    type={button.type}
                    class={button.class}
                    name={button.name}
                  />
                ))}
              </Row>
            </Container>
          }
        />
      ));
    
      return (
        ...
      );
    };

    reducer 程式碼、操作類型、操作建立者...全部由單一狀態切片取代。

    import { createSlice } from "@reduxjs/toolkit";
    
    const initialState = {
      cardsData: {},
      ... other home page state ...
    };
    
    const homePageSlice = createSlice({
      name: "homePage",
      initialState,
      reducers: {
        addCardsData: (state, action) => {
          state.cardsData = action.payload;
        },
        ... other reducer cases ...
      }
    });
    
    export const {
      addCardsData,
      ... other generated actions ...
    } = homePageSlice.actions;
    
    export default homePageSlice.reducer;
    

    回覆
    0
  • 取消回覆