You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native跨组件修改状态:Todo应用Modal无法关闭

问题分析与解决方案

问题根源

你在AddTodo和GetInfoDialog中分别调用了useChange自定义Hook,每次调用Hook都会生成独立的状态实例。也就是说,GetInfoDialog里修改的state是它自己的局部状态,和AddTodo中控制Modal显示的state完全无关,所以点击Cancel按钮无法关闭弹窗。

解决方案

将AddTodo中的状态控制逻辑通过props传递给GetInfoDialog,让子组件直接调用父组件的状态修改方法,确保操作的是同一个状态。


修改后的AddTodo.js

import { Modal, StyleSheet, Text, TouchableOpacity, View } from "react-native";
import { GetInfoDialog } from "./GetInfoDialog";
import { React, useState } from "react";

function useChange() {
  const [state, setState] = useState(false);
  function change(value) {
    setState(value);
    console.log("state: " + value);
  }

  return { state, change };
}

function AddTodo() {
  const { state, change } = useChange();

  return (
    <View style={styles.container}>
      <Modal
        animationType="slide"
        transparent={true}
        visible={state}
        style={styles.itemsContainer}
      >
        {/* 将关闭弹窗的方法通过props传给子组件 */}
        <GetInfoDialog onCancel={() => change(false)} />
      </Modal>

      <TouchableOpacity
        style={styles.btn}
        onPress={() => {
          change(true);
        }}
      >
        <Text style={styles.text}>Add New</Text>
      </TouchableOpacity>
    </View>
  );
}

// 补充样式(根据你的需求调整)
const styles = StyleSheet.create({
  container: {
    margin: 16,
  },
  btn: {
    backgroundColor: "#2196F3",
    padding: 12,
    borderRadius: 8,
    alignItems: "center",
  },
  text: {
    color: "#fff",
    fontSize: 16,
    fontWeight: "500",
  },
  itemsContainer: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
});

export default AddTodo;

修改后的GetInfoDialog.js

import React, { useState } from "react";
import {
  StyleSheet,
  Text,
  TextInput,
  TouchableOpacity,
  View,
} from "react-native";

// 通过props接收父组件传递的关闭方法
function GetInfoDialog({ onCancel }) {
  return (
    <View style={styles.container}>
      <Text style={styles.headerText}>Add Todo</Text>
      <TextInput style={styles.input} placeholder="Enter todo content" />
      <View style={styles.btnContainer}>
        <TouchableOpacity style={styles.btn}>
          <Text style={styles.text}>Add</Text>
        </TouchableOpacity>
        <TouchableOpacity
          style={styles.btn}
          onPress={onCancel} // 直接调用父组件传来的关闭方法
        >
          <Text style={styles.text}>Cancel</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

// 补充样式(根据你的需求调整)
const styles = StyleSheet.create({
  container: {
    backgroundColor: "#fff",
    padding: 24,
    borderRadius: 12,
    width: "80%",
    alignItems: "center",
  },
  headerText: {
    fontSize: 20,
    fontWeight: "bold",
    marginBottom: 16,
  },
  input: {
    borderWidth: 1,
    borderColor: "#ccc",
    borderRadius: 8,
    padding: 12,
    width: "100%",
    marginBottom: 16,
  },
  btnContainer: {
    flexDirection: "row",
    gap: 12,
  },
  btn: {
    backgroundColor: "#2196F3",
    padding: 12,
    borderRadius: 8,
    alignItems: "center",
    width: 80,
  },
  text: {
    color: "#fff",
    fontSize: 16,
  },
});

export default GetInfoDialog;

额外注意点

  1. 修正了GetInfoDialog.js中import react的拼写错误,改为import React(首字母大写),避免React Native报错。
  2. 给两个组件都添加了export default,确保组件能被正确引用。

内容的提问来源于stack exchange,提问作者Kuber D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 19:33:23