【问题标题】:React Native - Cascade state updates from parent to childReact Native - 从父级到子级的级联状态更新
【发布时间】:2019-10-14 21:52:38
【问题描述】:

我正在尝试将状态更改从父组件级联到子组件。

export default class App extends React.Component {
  constructor(props) {
    super(props);

    this.listUpdater = new_list_updater();

    this.state = {
      schoollist: this.listUpdater.update_list(),
    }
  } 

  listUpdateCallback = () => {
    console.log("Callback triggered!");
    console.log(this.state.schoollist.slice(1,3));
    this.setState({schoollist: this.listUpdater.update_list()});
    console.log(this.state.schoollist.slice(1,3));
  }

  render() {
    return (
      <SafeAreaView style={styles.container}>
        <Header updateCallback={this.listUpdateCallback}/>
        <SchoolList school_list={this.state.schoollist}/>
      </SafeAreaView>      
    );
  }
}

listUpdater.update_list() 是一个类中的一个方法,它实现了 getISchools 和 ShuffleArray 并存储了正在被洗牌的学校列表。它返回洗牌的学校列表。

import { shuffleArray } from './Shuffle'
import { getISchools } from './iSchoolData'

class ListUpdater{
    constructor() {
        console.log("Initiating class!");
        this.currentSchoolList = [];
    }

    update_list() {
        console.log("Updating list!");
        if (this.currentSchoolList.length == 0){
            this.currentSchoolList = getISchools();        
        }
        else{
            shuffleArray(this.currentSchoolList);
        }
        return(this.currentSchoolList);
    }
}

export function new_list_updater(){
    return new ListUpdater();
}

据我所知,一切正常。当我按下 Header 组件中的刷新按钮时,它会触发 updateCallback,它会更新存储在状态变量中的列表(通过登录到控制台和 ComponentDidUpdate() 来验证)

这是未刷新的组件:

import React from 'react';
import { StyleSheet, Text, View, SafeAreaView, FlatList } from 'react-native';

export default class SchoolList extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <SafeAreaView style={styles.listArea}>
                <FlatList
                data = {this.props.school_list}
                renderItem = {({item}) =>
                    <View style={styles.row}>
                        <View style={styles.num_area}>
                            <Text style={styles.num_text}>{item.key}</Text>
                        </View>
                        <View style={styles.text_area}>
                            <Text style={styles.univ_text}>{item.univ}</Text>
                            <Text style={styles.school_text}>{item.school}</Text>
                        </View>
                    </View>
                }
                />
            </SafeAreaView>
        );
    }

    componentDidUpdate(){
        console.log("SchooList Updated!");
    }
}

我期待的流程是:

  1. Parent 将 updateCallback 引用传递给 Header(子)

  2. Header 中的刷新按钮触发 Parent 中的 updateCallback

  3. Parent 中的 updateCallback 使用 setState 更新状态

  4. 使用状态变量的父级和相关子级重新渲染,显示新列表

1-3 似乎有效,4 无效!

【问题讨论】:

  • 如果您将componentDidUpdate() 生命周期添加到AppSchoolList,当您单击Header 中的刷新时它会触发吗?我做了一个小例子来说明你在 ReactJS 中所做的事情,但无法重现问题
  • @Anthony 我将 componentDidUpdate() 添加到 App 和 SchoolList 中,并在我单击刷新按钮时验证它会为两者触发。我为不刷新的 SchoolList 组件添加了代码,如果有帮助的话
  • 你能在SchoolListcomponentDidUpdate() 中注销prevPropsthis.props 吗?
  • 谢谢 - 当我注销 this.props 时,它显示它正在使用新的洗牌列表进行更新。我不确定为什么不使用新值重新渲染平面列表

标签: javascript react-native


【解决方案1】:

当您出于某种原因使用 setState 时,您的组件可能不会重新渲染。尝试在渲染方法中添加警告来检查这一点。我还注意到您正在更改数组 this.currentSchoolList,绞盘作为您的状态的参考传递(所有对象都作为参考传递)。尝试在调用 shuffleArray(this.currentSchoolList) 之前替换它,制作数组的副本。

你可以这样复制数组(这是 ES6 sintax): newArray = [...oldArrray]; 或者使用其他方法。

【讨论】:

  • 这最终修复了它!我以为我可以将原始数组打乱,它会起作用,但也许 setState 没有更新,因为它仍在引用原始引用?不完全确定 - 但创建一个副本并改组它,然后用副本更新状态最终修复它。
  • 在 React 中你不应该直接改变状态。当你使用 setState 时,React 会将当前状态与之前的状态进行比较,以了解是否有任何变化。可能这里发生的事情是你改变了状态,然后用 setState() 设置它。所以 React 比较了当前的变异状态和你传递给 setState() 的新状态,结果是一样的!所以,对于 React,什么都没有改变。
猜你喜欢
  • 1970-01-01
  • 2020-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-29
  • 1970-01-01
  • 2018-08-17
相关资源
最近更新 更多