【问题标题】:Component Re-renders after clicking NavLink & loads same data Multiple times单击 NavLink 并多次加载相同数据后组件重新渲染
【发布时间】:2020-09-16 23:11:53
【问题描述】:

我已经制作了一个示例电子商务网站以供练习,并且我使用了 React、Redux 和 Router-DOM。第一次,一切都完美加载。它有两条路线ScreenShot-LinkHome 路由将我带到出现问题的主页,而 Upload 路由将我带到上传页面。但是当我再次返回 HomeRoute 时,从 API 获取的数据 不会重新渲染 > 状态加倍我的意思是现有状态保持不变,但由于某种原因,数据被再次获取,元素被渲染 2 次ScreenShot-2-Link

如果我从另一条路线返回它,身体元素会加倍......

const Body = ({getProducts, deleteProduct, productState})=>{
    const {products, loading, error} = productState;

    useEffect(()=>{
        getProducts()
    }, [getProducts])

    const deleteProducts = (id)=>{
        deleteProduct(id)
    }

    return (
        <div className="display-flex width-full flex-wrap justify-content-center">
            {!loading && !error && products?products.map(product=>(
                product.data?product.data.map(d=>(
                    <BodyDiv
                        key={uuid.v4()}
                        imgSrc={d.imgSrc}
                        title={d.title}
                        details={d.details}
                        description={d.description}
                        onClick={()=>deleteProducts(d._id)}
                    />    
                )):product.map(d=>(
                    <BodyDiv
                    key={uuid.v4()}
                    imgSrc={d.imgSrc}
                    title={d.title}
                    details={d.details}
                    description={d.description}
                    onClick={()=>deleteProducts(d._id)}
                /> 
                ))
            ))
            : loading&&!error
            ? <div className="vertical-center-strict horizontal-center-strict">Loading.......</div>
            : <div className="vertical-center-strict horizontal-center-strict">No Internet!</div>
        }
        </div>
    )
}

const BodyDiv = (props)=>{
    return(
        <div className="container-div width-full card tiny-padding align-self-start">
        <img title={props.title} className="img-responsive hover-filter" src={props.imgSrc}/>
        <h2 className="text-align-center">{props.title}</h2>
        <h5>{props.details}</h5>
        <p className="text-align-justify">{props.description}</p>
        <button 
        className="btn btn-danger"
        onClick={props.onClick}
        >Delete</button>
        </div>
    )   
} 


BodyDiv.propTypes = {
    title: PropTypes.string.isRequired,
    img: PropTypes.string,
    details: PropTypes.string.isRequired,
    description: PropTypes.string,
    onClick: PropTypes.func

}
const mapStateToProps = (state)=>({
    productState: state.productState
})
const conn = connect(mapStateToProps, {getProducts, deleteProduct})(Body)

export default conn;

路由器组件和导航组件

//Parent Router Comonent
const App = () => {
  return (
    <Router>
      <AppNavBar />
      <Switch>
        <Route path="/" exact>
          <Body />
        </Route>
        <Route path="/upload">
          <Upload />
        </Route>
        <Route path="*">
          <div className="vertical-center-strict top-20">
          <h1 className="text-align-center">404</h1>
          <h3>Page doesn't exist</h3>
          <p>Please give the correct address!</p>
          </div>
        </Route>
      </Switch>
    </Router>
  );
};

export default App;


//NavLink Components..
const NavBar = ()=>{
return(
<>
 <NavLink activeClassName="link" to="/" exact>
    <NavItem content="Home" /> //<a> element with content as a prop 
 <NavLink>
 <NavLink activeClassName="link" to="/upload">
    <NavItem content="Upload" 
 </NavLink>
</>
         )
       }
}

我的 Redux 代码:Store 和 Reducers

//Store
import {createStore, applyMiddleware} from "redux"
import rootReducer from "./reducers/index"
import thunk from "redux-thunk"


const middleWare = [thunk]

const store = createStore(rootReducer, applyMiddleware(...middleWare))

export default store


//RootReducer
import {
  FETCHED_PRODUCTS,
  FETCHING_PRODUCTS,
  ERROR_GET_PRODUCTS,
  DELETED_PRODUCT,
  ERROR_DELETING_PRODUCT
} from "../actions/productActions";

const initialState = {
  products: [],
  loading: true,
  error: false,
};

const productReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCHING_PRODUCTS:
      return {
        ...state,
        loading: true,
      };
    case FETCHED_PRODUCTS:
      return {
        ...state,
        products: state.products.concat(action.payload),
        loading: false,
        error: false,
      };
    case ERROR_GET_PRODUCTS:
      return {
        ...state,
        loading: false,
      };
    case DELETED_PRODUCT:
      return {
        ...state,
        products: state.products.map((product) =>
          product.data.filter((d) => d._id !== action.payload)
        ),
        error: false,
      };
    case ERROR_DELETING_PRODUCT:
      return {
        ...state,
        error: true,
      };
    default:
      return state;
  }
};

export default productReducer;

动作创作者

export const getProducts = (payload)=>(dispatch)=>{
    return(
     fetch("/api/products")
    .then(res=>{
        dispatch({
            type:FETCHING_PRODUCTS
        })
        if(!res.ok){
            dispatch({
                type: ERROR_GET_PRODUCTS
            })
        }
    return res.json();
    })
    .then(json=>{
        if(json)dispatch({
        type: FETCHED_PRODUCTS,
        payload: json
    })
})
    .catch(err=>{
        console.log("Error!! failed to fetch data: "+ err)
    })
    )
} 




export const deleteProduct = (payload)=>dispatch=>{
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");

var requestOptions = {
  method: 'DELETE',
  headers: myHeaders,
  body: JSON.stringify({"_id": payload}),
  redirect: 'follow'
};
    fetch("/api/product-delete", requestOptions).then(res=>{
        dispatch({
            type: DELETED_PRODUCT,
            payload
        })
        if(res.status === 501 || res.status === 403){
             dispatch({
                 type: ERROR_DELETING_PRODUCT,
             })
         }
    })
    .catch(err=>{
        console.log("Failed to Delete")
    })
}

请帮助我,我一直在寻找解决方案 4 小时...如果您能帮助我,那就太好了...提前致谢

【问题讨论】:

    标签: reactjs redux react-redux fetch react-router-dom


    【解决方案1】:

    当使用useEffect 钩子时,第二个参数是依赖项。所以如果依赖项发生变化,它会再次调用该函数。现在因为getProducts是一个函数,它永远不会被再次调用。相反,你应该把products in there

    useEffect(()=>{
            getProducts()
        }, [products])
    //will refetch data everytime product state is updated.
    

    有点难以看出,代码中发生了什么。但我怀疑这可能是问题所在。否则请告诉我。

    【讨论】:

    • 对于函数,我可以使用useCallback 包装它并将其作为第二个参数传递给使用效果吗?与您的实践相比有什么不同吗?非常感谢
    • @baileyhaldwin,这比以前更糟了。当我从任何其他路线返回到这条路线时,它渲染了两次之前..现在,它总是重新渲染......还有其他方法可以解决这个问题吗?感谢您的回答...抱歉上传太多代码...
    猜你喜欢
    • 2019-07-20
    • 2018-05-17
    • 1970-01-01
    • 2020-05-21
    • 1970-01-01
    • 2021-12-15
    • 2019-01-13
    • 1970-01-01
    • 2021-05-03
    相关资源
    最近更新 更多