渲染动态渲染列表React / Redux时使用的旧道具

时间:2019-12-01 19:12:00

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

我正在渲染通过映射在数组上创建的内容,该数组返回一个单独显示项目的数组。我正在使用商店中的索引位置来确定正在显示的卡。这很好用,但是当我实现一个onClick事件时,该事件从商店中获取当前使用的索引Im,然后使用商店中的索引将内容推入数组,事情开始崩溃。它返回初始索引值而不是当前索引值。由于我在实际的render方法中使用了索引值,因此它仅与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存储,我在这里将两者分开只是为了测试这种渲染和动画卡片的方法,而不必为我编写其他动作创建者和reducer cardDeck)

1 个答案:

答案 0 :(得分:0)

您似乎在props.cardIndex数组中缺少依赖项useEffect,导致它在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. 动作应告诉减速器什么,而不是如何。他们应该描述发生了什么动作,而不是减速器应该如何更新状态。这样可以将状态的所有逻辑都放在一个地方(约简器),并清晰地将关注点分离。代替pushItemToReadingListincreaseCardIndex,您可以分派单个动作addItemToReadingList,然后让reducer负责将其添加到存储的列表中并增加索引。