【问题标题】:React Native -- .Map() items in Child won't rerender after Child event handler updates Parent's stateReact Native - Child 事件处理程序更新 Parent 的状态后,Child 中的 .Map() 项目不会重新呈现
【发布时间】:2018-08-05 09:28:16
【问题描述】:

在我的项目中,在使用 .map() 函数循环遍历数据文件时,我将一个函数 (updatestate) 从父组件 App 传递给子组件 Main,它允许Child 调用 .setState() 并在 Parent 状态下追加到数组。

但是,当我调用这个函数来设置 Parent 的状态时,映射部分 -- {contents} -- 除非我点击再次屏幕。

有什么想法吗?我是否缺少一些绑定或需要做一些 componentDidMount 或任何事情?我尝试在 eventHandler 中添加this.forceUpdate(),但**映射的{contents} 部分** 仍然不会自动呈现。

const RootStack = StackNavigator(
  {
    Main: {
      screen: Main}
  }
);

export default class App extends Component<{}> {
    constructor(props) {
      super(props);
      this.state = {
        favoritesList: []
      };
    }

  updateArr=(itemname, url)=>{this.setState({ favoritesList: [...this.state.favoritesList, {"item_name":itemname, "url":url}]})};

  render() {
      return <RootStack screenProps={{appstate: this.state,
                                    updatestate: this.updateArr}}
      />;
    }
  }

class Main extends React.Component {

  render() {
    var updatestate = this.props.screenProps.updatestate;

    //collection is the data (local JSON) i'm looping thru via .map in Main Component

    const contents = collection.map((item, index) => {
        return (
            <Card key={index}
                  onSwipedRight={() => {updatestate(item.item_name,item.url)}}
            >
              <View> //THIS and anything after <Card> doesn't render for the next card automatically if I do 'onSwipedRight'
                <Image
                    source={{uri: item.url}} />
               </View>
            </Card>
        )
      },this);

      return (
      <View>
            <CardStack>

              {contents} //THIS IS THE PART THAT WON'T AUTO-RERENDER AFTER THE EVENT HANDLER THAT SETS THE PARENT'S STATE

            </CardStack>
      </View>
        );
    }
}

为了确保事件处理程序没有问题,我添加了一个不设置父级状态的函数,并让&lt;Card&gt; 在事件处理程序上调用它——它工作得很好,孩子组件&lt;Card&gt; 完美呈现。似乎是从父级传递给子级的updatestate 函数在上游调用.setState(),由于某种原因导致子级无法渲染/未完成渲染映射的{contents} 在事件处理程序之后。

class Main extends React.Component {
  render() {

    var updatestate = this.props.screenProps.updatestate;

    var newfunc = (a, b) => {console.log('a:', a, 'b:', b)};

      const contents = collection.map((item, index) => {
        return (
            <Card key={index}
                  newfunc(item.item_name,item.item_name);}}
                  // onSwipedRight={() => {updatestate(item.item_name,item.url); }}
                  >

【问题讨论】:

    标签: javascript reactjs react-native react-component


    【解决方案1】:

    尝试像这样重写你的 setState

    import { InteractionManager } from "react-native";
    
    updateArr = (itemname, url) => {
      InteractionManager.runAfterInteractions(() => {
        this.setState( prevState => ({
          favoritesList: [...prevState.favoritesList, {       "item_name":itemname, "url":url } ]
        });
      });
      
    }
    
    // add this line to your parent component constructor()
    this.updateArr = this.updateArr.bind(this);

    此外,我建议您将您的 React.Component 更改为 React.PureComponent ,而不是它会为您处理状态更改的浅相等并降低性能。 供参考React.Component vs React.PureComponent

    【讨论】:

    • :( 该建议仍然没有运气 - 父母的状态正在正确更新(就像以前一样),但是在 onSwipedRight 映射部分的事件之后,{contents} 没有呈现.
    • 我想知道滑动的动画是否不允许状态正确更新。尝试使用 InteractionManager.runAfterInteractions(() => { this.setState( ... ) }) 将 setState 包装在 updateArr 中,也在您的应用程序(父组件)中将此行添加到构造函数 this.updateArr = this。 updateArr.bind(this);
    • 哦,听起来可能就是它!尽管使用这种格式,但在您上一条评论中实施您的建议时,我遇到了一些问题——您能否以代码形式将其添加到您的答案中?非常感谢!
    【解决方案2】:

    尽量不要将index 用作key。有意义的键值有助于引擎找出需要重绘的内容。

    在你的情况下,我建议首先使用key={item.url}

    https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318

    【讨论】:

      猜你喜欢
      • 2021-06-25
      • 2020-05-07
      • 1970-01-01
      • 1970-01-01
      • 2021-05-09
      • 1970-01-01
      • 2021-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多