【问题标题】:React Native: this.state of reusable components not expectedReact Native:不期望可重用组件的 this.state
【发布时间】:2017-01-12 05:06:21
【问题描述】:

我是 React Native 的新手,老实说,我对 React 有非常基本的了解。我正在开发一个使用reusable componentsES6 sintax 的示例应用程序。

在同一个场景中多次重用同一个组件时,我遇到了意想不到的结果(我也使用了 Navigator)。更准确地说,我无法理解为什么不同的组件(相同类型)显然是彼此状态的条件。

我发布我的代码是为了更好地理解。

这是我的主页,我在其中使用了 2 次相同的自定义组件

HomeScene.js

import React from 'react';
import {View} from 'react-native';

import BaseScene from './BaseScene'
import SearchSuggest from '../components/SearchSuggest';
import TopCategories from '../components/TopCategories'

import styles from '../styles'


export default class HomeScene extends BaseScene {
  render() {
    return(
      <View style={styles.container}>
        <SearchSuggest
          navigator={this.props.navigator}
        />

        <TopCategories/> //first 

        <TopCategories/> //second

      </View>
    )
  }
}

这些是使用的内部组件的详细信息:

TopCategories.js

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

import styles from '../styles'
import utility from '../utility'
import serverConnector from '../serverConnector'
import routes from '../routes'

import MenuItemComplex from './MenuItemComplex'

export default class TopCategories extends Component {

  constructor(props) {
    super(props);
    this.state = {categories: []};
    this._fetchContent();
  }


  _updateCategoriesList(rawCategories){
    //store in state.categories array a simplied version of         
    //the contents received from the server

    let simplifiedCategories = [];
    for(i=0; i<rawCategories.length; i++){
      var simpleCat = {};
      simpleCat.id = rawCategories[i].uniqueID;
      simpleCat.name = rawCategories[i].name;
      simplifiedCategories.push(simpleCat);
    }

    this.setState({categories: simplifiedCategories });
  }

  _fetchContent(){
    //fetch content from server in JSON format 
    _topCategories = this;
    serverConnector.call(
      "CATEGORY",
      "FindTopCategories",
      {},
      function(err, json){
        if(err!=null) utility.log("e", err);
        else {
          try{
            _topCategories._updateCategoriesList(json.res.header.body.CatalogGroupView);
          }catch(err){
            utility.log("e", err);
          }
        }
      }
    )
  }

  openCategoryScene(id, name){
    //push on Navigator stack the next route with additional data
    let nextRoute = routes.get("categoriesListFirst");
    nextRoute.passProps = {
      categoryId: id,
      categoryName: name
    };
    this.props.navigate(nextRoute)
  }

  render(){
    console.log(this.state)
    return (
      <MenuItemComplex key="categories" name="Catalogo" icon="list-b" onItemSelected={this.openCategoryScene.bind(this)} subItems={this.state.categories} />
    )
  }
}

最后 MenuItemComplex.js

import React, { Component } from 'react';
import { View, Text, Image, TouchableHighlight, TouchableWithoutFeedback } from 'react-native';

import styles from '../styles'

export default class MenuItemComplex extends Component{

  static propTypes = {
    name : React.PropTypes.string.isRequired,
    icon : React.PropTypes.string.isRequired,
    subItems: React.PropTypes.array.isRequired,
    onItemSelected: React.PropTypes.func.isRequired
  };

  render(){
    let subItems = [];
    for(i=0; i<this.props.subItems.length; i++){
      let subItem = this.props.subItems[i];
      subItems.push(
        <TouchableHighlight
          key={subItem.id}
          underlayColor={"#d00"}
          activeOpacity={1}
          onPress={() => this.props.onItemSelected(subItem.id, subItem.name)}
        >
          <View style={styles.menuSubItem}>
            <Text style={[styles.mmText, styles.menuSubItemText]} >
                {subItem.name}
            </Text>
          </View>
        </TouchableHighlight>
      )
    }

    return(

      <View>
        <TouchableWithoutFeedback disabled={true}>
          <View style={styles.menuItem}>
            <Image style={styles.menuItemImage} source={{uri: this.props.icon}} />
            <Text style={[styles.mmTextBold, styles.menuItemText]}>{this.props.name}</Text>
          </View>
        </TouchableWithoutFeedback>

        {subItems}

      </View>
    )
  }
}

我不明白为什么在我的 HomeScene 中使用的第一个 组件的 state.simplifiedCategories 在第二个 组件渲染后似乎是一个空数组。到目前为止,我认为这两个组件是完全隔离的,具有自己的“私有”状态。但在这种情况下,似乎这是以某种方式共享的。

有人可以解释这里发生了什么吗?然后我该如何解决呢?

谢谢

编辑 2016/09/05 正如用户 V-SHY 所建议的,我试图给每个组件一个随机字符串作为键,但这并不能解决问题。 我觉得很奇怪的是,在全局窗口对象中,我只能看到 的一个实例,最后一个。

这里的截图指的是用

做的测试
 <TopCategories key="tc_first" {...this.props}/>

 <TopCategories key="tc_second" {...this.props}/>

HomeScene.js 文件中

【问题讨论】:

  • 尝试为 HomeScene 中的 组件提供不同的键?并尝试为 TopCategories render() 中的 MenuItemComplex 组件提供动态键而不是“类别”的常量键?好像,当第二个 组件开始渲染时,第一个 组件的状态被重置,您使用相同的键渲染两个 MenuItemComplex 组件,我想知道这是您问题的根源。
  • 嗨 V-SHY,我尝试了你的建议但没有成功。特别是我试图给每个子组件一个随机字符串作为键,但这并不能解决问题。我正在更新原始问题,添加有关 console.log(window) 的信息
  • 如果它们有单独的键,则不会发生这种行为,尤其是当文件本身没有变量时。我建议给他们一个不同的 prop 值来区分它们,然后添加 console.logs 来调试正在发生的事情。我建议这是数据获取或突变的问题。
  • 谢谢@DanielSchmidt!这确实是一个与从服务器获取数据机制有关的问题。我正在用问题和我的解决方案更新问题
  • @AndreaDiLisio 太棒了!

标签: reactjs react-native


【解决方案1】:

正如 Daniel 所建议的,在从服务器获取数据的过程中出现了问题。特别是在 TopCategories.js 文件中创建 _topCategories=this 对象时我错了

_fetchContent(){
    _topCategories = this; // ISSUE HERE!
    serverConnector.call(
      "CATEGORY",
      "FindTopCategories",
      {},
      function(err, json){
        if(err!=null) utility.log("e", err);
        else {
          try{
            _topCategories._updateCategoriesList(json.res.header.body.CatalogGroupView);
          }catch(err){
            utility.log("e", err);
          }
        }
      }
    )
  }

我解决了将组件的引用传递给 fetchContent 方法:

constructor(props) {
    super(props);
    this.state = {categories: []};
    this._fetchContent(this); // passing THIS reference
  }


  _updateCategoriesList(rawCategories){
    let simplifiedCategories = [];
    for(i=0; i<rawCategories.length; i++){
      var simpleCat = {};
      simpleCat.id = rawCategories[i].uniqueID;
      simpleCat.name = rawCategories[i].name;
      simplifiedCategories.push(simpleCat);
    }

    this.setState({categories: simplifiedCategories});
  }

  _fetchContent(instanceRef){
    motifConnector.call(
      "CATEGORY",
      "FindTopCategories",
      {},
      function(err, json){
        if(err!=null) utility.log("e", err);
        else {
          try{
            instanceRef._updateCategoriesList(json.res.header.body.CatalogGroupView);
          }catch(err){
            utility.log("e", err);
          }
        }
      }
    )
  }

【讨论】:

  • 构造函数中的this._fetchContent = this._fetchContent.bind(this); 和_fetchContent() 函数的try 语句中的this._updateCategoriesList(json.res.header.body.CatalogGroupView); 怎么样?请参阅步骤 3 - 将实例方法/回调从 newmediacampaigns.com/blog/… 绑定到实例
猜你喜欢
  • 2020-10-02
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-11
相关资源
最近更新 更多