【问题标题】:Old props being used when rendering dynamically rendered list React/Redux渲染动态渲染列表 React/Redux 时使用的旧道具
【发布时间】:2020-03-26 11:31:02
【问题描述】:

我正在渲染通过映射一个数组创建的内容,该数组返回一个单独显示项目的数组。我正在使用我商店的索引位置来确定显示的是什么卡。这很好用,但是当我实现一个 onClick 事件时,该事件从存储中获取我使用的当前索引,然后使用存储中的索引将内容推送到数组中,事情开始崩溃。它返回初始索引值而不是当前索引值。这只是与 onClick 事件隔离,因为我在实际渲染方法中使用索引值并且它的行为符合预期。我假设这种行为正在发生,因为当我在组件安装时映射列表时,它绑定了初始值的道具而不传递更新的值?这是有问题的代码

// 这是创建卡片列表的钩子

const [cardDeck, setCardDeck] = useState([])
    useEffect(()=>{
        renderCardArray();
    },[props.news])

// 这是调用动作创建者的函数

    const addToList = () =>{
        props.pushItemToReadingList(props.news[props.cardIndex]);
        props.increaseCardIndex();
}

// 这是设置为状态值的地图,我可以单独显示

const renderCardArray = () =>{
    if(props.news.length > 1 && props.cardIndex < props.news.length){
        setCardDeck(props.news.map((item,iter)=>{
            return(
                <div className="card" ref={drag} key={iter}>
                    <h3>{item.title}</h3>
                    <img src={item.urlToImage} alt='News' style={{maxWidth: '200px'}} />
                    <button onClick={props.increaseCardIndex}>X</button>
                    <button onClick={addToList}>{'<3'}</button>
                </div>
            )
            }))`

// 2ed 按钮每次点击都会返回 0 的索引,但卡片会在最终返回时更新为正确的索引 // 这里是组件的最终返回值

return (
        <div>
            {cardDeck[props.cardIndex]}
        </div>
    )
}

// 最后是connect和mapStateToProps

const mapStateToProps=(state)=>{
return {news: state.news, cardIndex: state.cardIndex}

}

export default connect(mapStateToProps,{
    pushItemToReadingList,
    increaseCardIndex
})(NewsCard);

如果有人可以帮助我理解为什么当我执行 addToList 函数时它没有收到组件其余部分正在接收的更新索引?还有更好的方法来为映射列表提供更新的道具吗?(我暂时解决了这个问题,方法是切换我的动作创建者不接受推送的参数,它只是在内部使用存储数据,但它对我没有帮助了解为什么会发生这种行为)(我也不打算使用本地状态和 redux 存储,我在这里将两者分开只是为了测试这种渲染和动画卡片的方法,而无需为我的卡片)

【问题讨论】:

    标签: javascript reactjs redux react-redux react-hooks


    【解决方案1】:

    您的useEffect 数组中似乎缺少依赖项props.cardIndex,导致props.cardIndex 更新时它不会更新:

    useEffect(()=>{
      if(props.news.length > 1 && props.cardIndex < props.news.length){
        renderCardArray();
      }
    // renderCardArray depends on `props.cardIndex`, so
    // make sure to add it here
    },[props.news, props.cardIndex])
    

    如果renderCardArray 的内容内联在useEffect 中会更清楚(除非您需要在其他地方调用该函数)。您还可以将 newscardIndex 传递给 renderCardArray 以更清楚地了解依赖关系。

    renderCardArray(props.news, props.cardIndex);
    

    我不确定这是否能解决您的问题,但这里有一些建议可能会使代码更易于推理/调试:

    1. key 使用比索引更稳定的值。如果元素被添加到数组中/从数组中删除,索引会发生变化,这可能会导致错误。如果item.title 对于每个项目都是唯一的,您可以使用它来代替。

    2. 在状态中设置数据,并将 JSX 限制为从组件返回的内容。看起来您一次只需要渲染一张卡片,甚至可能不需要在本地状态中存储任何内容:

    const item = props.news[props.cardIndex];
    
    return (
      <div className="card" ref={drag}>
        <h3>{item.title}</h3>
        <img src={item.urlToImage} alt='News' style={{maxWidth: '200px'}} />
        <button onClick={props.increaseCardIndex}>X</button>
        <button onClick={addToList}>{'<3'}</button>
      </div>
    )
    

    如果您确实需要保持一组卡片的状态,请保留数据而不是 JSX,并在返回时映射 cardDeck 数据:

    const [cardDeck, setCardDeck] = useState([])
    
    useEffect(()=>{
      if(props.news.length > 1 && props.cardIndex < props.news.length){
        setCardDeck(props.news);
      }
    },[props.news, props.cardIndex]);
    ...
    return (
      cardDeck.map(card => (
        <div className="card" ref={drag} key={card.title}>
          <h3>{card.title}</h3>
          <img src={card.urlToImage} alt='News' style={{maxWidth: '200px'}} />
          <button onClick={props.increaseCardIndex}>X</button>
          <button onClick={addToList}>{'<3'}</button>
        </div>
      )
    )
    
    1. 操作应该告诉减速器什么,而不是如何。他们应该描述发生了什么动作,而不是 reducer 应该如何更新状态。这将状态的所有逻辑保存在一个地方(reducer),并清晰地分离了关注点。代替pushItemToReadingListincreaseCardIndex,您可以调度单个操作addItemToReadingList 并让reducer 负责将其添加到存储列表并增加索引。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-15
      • 2021-10-23
      • 2017-06-02
      • 1970-01-01
      • 1970-01-01
      • 2016-02-22
      • 1970-01-01
      • 2022-01-02
      相关资源
      最近更新 更多