【问题标题】:Multiple Components with same state name, how to change one state of one component without affecting the others?具有相同状态名称的多个组件,如何更改一个组件的一种状态而不影响其他组件?
【发布时间】:2019-06-14 10:15:10
【问题描述】:

在我的本机反应程序中,我有一个组件 (Bell),它为从 API 调用的每个项目/列表调用。铃铛用于在按下时发出通知(并取消它),我创建了一个状态(isBellActive)来确定铃铛是否已打开。如果是,则 isBellActive 为真,否则为假。我通过 asyncStorage 存储数据。

我遇到的问题是,如果我更改一个铃铛的状态(在一个项目/列表上)然后关闭应用程序并重新启动,该铃铛的状态更改将影响所有其他铃铛组件的 isBellActive 状态。如何使状态(即使它们都共享相同的名称)保留在一个特定的项目/列表中

铃铛组件类

export default class Bell extends React.Component {
  constructor(props) {
    super(props);  
    this.state = {
      isBellActive:  null,

    };
  }

  componentDidMount = ()=>{
    AsyncStorage.getItem('isBellActive').then(value => this.setState({ isBellActive: JSON.parse(value) }));
  }

  setTrue(){
    AsyncStorage.setItem('isBellActive', JSON.stringify(true)).then(() => {
      this.setState({ isBellActive: true});
    });
  }

  setFalse(){
    AsyncStorage.setItem('isBellActive', JSON.stringify(false)).then(() => {
      this.setState({ isBellActive: false});
    });
  }

  render() {
     return (
      <Ionicons

        name={this.state.isBellActive? "md-notifications":"md-notifications-off"}
        color={"white"}
        size={30}
        style={styles.NotifIcon}
        onPress={() => {       
            Vibration.vibrate()
             if(this.state.isBellActive == false){             
                  PushNotificationIOS.scheduleLocalNotification({
                    userInfo:{
                      ID: this.state.ID
                    },
                    alertTitle: "Launching Soon:",
                    alertBody: this.state.alertBody,
                    fireDate: this.state.fireDate // in 30 mins
                    });
                    this.setTrue()
                    this.setState({Key:true})
                  }
                  else if(this.state.isBellActive != false){
                    PushNotificationIOS.cancelLocalNotifications({ID:this.state.ID});
                    this.setFalse()
                  }
                }
            }
         }}
       />
    );
  }
}

调用组件的类

export default class LaunchingScreen extends React.Component{
 let launches = this.state.dataSource.map((item, key) => {
   ..
   <View>
    ..
    <Bell />
    ..
   </View>
     ..
  }
}

更新 这是在调用组件的类中,它得到一个包含所有信息的 JSON:

componentDidMount(){
    return fetch("https://launchlibrary.net/1.4/launch/next/20")
      .then(response => response.json())
      .then(responseJson => {
        this.setState({
          isLoading: false,
          dataSource: responseJson.launches
        }); 
      })
      .catch(error => {
        console.log(error);
      });
  }

【问题讨论】:

  • 由于每个Bell 组件都在访问AsyncStorage 中的相同键isBellActive,因此在重新启动时每个组件都具有最后更新的值。您需要为每个组件分开AsyncStorage 的键。 dataSource 记录长什么样,它们有什么唯一可识别的属性吗?
  • datasource 从 API 获取一个 JSON 文件,并且创建的每个列表都有自己的名称,彼此不同...我发个图片和代码是什么样的

标签: react-native async-await components local-storage


【解决方案1】:

根据您共享的 API 的响应,看起来id 属性是唯一的,您可以使用该属性为Bell 组件唯一定义key,并使用该key 来存储/从AsyncStorage 检索数据。请考虑以下代码 sn-ps

更改LaunchingScreen以添加key={item.id}

export default class LaunchingScreen extends React.Component{
  let launches = this.state.dataSource.map((item, key) => {
    ..
    <View>
    ..
    <Bell key={item.id}/>
    ..
    </View>
    ..
  }
}

现在在Bell 组件中,使用key 属性访问来自AsyncStorage 的数据

export default class Bell extends React.Component {
  constructor(props) {
    super(props);  
    this.state = {
      isBellActive:  null
    };
    this.accessKey = `${props.key}-isBellActive`;
  }

  componentDidMount = ()=>{
    AsyncStorage.getItem(this.accessKey).then(value => this.setState({ isBellActive: JSON.parse(value) }));
  }

  setTrue(){
    AsyncStorage.setItem(this.accessKey, JSON.stringify(true)).then(() => {
      this.setState({ isBellActive: true});
    });
  }

  setFalse(){
    AsyncStorage.setItem(this.accessKey, JSON.stringify(false)).then(() => {
      this.setState({ isBellActive: false});
    });
  }

  render() {
     return (
      <Ionicons

        name={this.state.isBellActive? "md-notifications":"md-notifications-off"}
        color={"white"}
        size={30}
        style={styles.NotifIcon}
        onPress={() => {       
            Vibration.vibrate()
             if(this.state.isBellActive == false){             
                  PushNotificationIOS.scheduleLocalNotification({
                    userInfo:{
                      ID: this.state.ID
                    },
                    alertTitle: "Launching Soon:",
                    alertBody: this.state.alertBody,
                    fireDate: this.state.fireDate // in 30 mins
                    });
                    this.setTrue()
                    this.setState({Key:true})
                  }
                  else if(this.state.isBellActive != false){
                    PushNotificationIOS.cancelLocalNotifications({ID:this.state.ID});
                    this.setFalse()
                  }
                }
            }
         }}
       />
    );
  }
}

在上述组件中,我们首先使用 this.accessKey = ${props.key}-isBellActive; 确定访问密钥,然后使用 this.accessKey 而不是 isBellActive

希望这会有所帮助!!!

【讨论】:

  • 您提供的代码在一定程度上有效。 props.key 有一个未定义的标签(但我认为这只是因为 item.ID 有点未定义?idk)所以我将 props.key 更改为 this.props.ID (props.ID 只是获取火箭发射的标题和不是数字),这似乎解决了它。 (有一个错误,但它似乎自行解决 - 编辑)
  • 好吧,我在评论中提到的错误似乎无法自行解决。正在发生的问题是我必须首先点击图标两次才能将其从关闭更改为打开,但之后只有一次(即使我关闭应用程序等也只有一次)。我相信这与 isBellActive 的初始化方式有关,但我将它从 null 更改为 false 但这并没有解决它。我还尝试在 componentDidMount 中执行 if 语句来查看 isBellActive 是否为 true/false/null,如果不是,则将 isBellActive 设置为 false。这有效,但在关闭应用程序后它总是恢复为 false。
  • JSON.parse(value) 的值是多少,是字符串还是布尔值,我猜是布尔值?另外,你需要else if(this.state.isBellActive != false)检查吗,我相信只有else可以工作?
  • 我在 getItem 之后放了一个 .then 来查找它提供的内容,起初它是未定义的。然后我在 componentDidMount 中的第一个 getItem 下放置了一个 getItem,它返回一个布尔值 false。我尝试使用 else not else if 并且问题仍然存在
猜你喜欢
  • 1970-01-01
  • 2021-08-01
  • 2021-10-18
  • 1970-01-01
  • 2019-12-08
  • 2022-01-19
  • 1970-01-01
  • 1970-01-01
  • 2017-03-24
相关资源
最近更新 更多