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

如何从子组件更新父函数组件的状态?

问题分析与解决方案

核心问题

  1. 索引参数传递错误:父组件渲染Item时未传递数组索引,子组件误用React内部的key属性作为业务索引,导致更新时找不到正确的数组项。
  2. 子组件状态与父组件不同步:父组件数据更新后,子组件本地text状态未同步title props的变化,显示内容不一致。
  3. 无效的useEffect触发:初始化阶段useEffect就调用onEdit,会错误覆盖父组件初始状态。

修复后的完整代码

import React, { useState, useEffect } from 'react';
import { SafeAreaView, View, StyleSheet, Text, StatusBar, TouchableOpacity, Modal, TextInput, Pressable } from 'react-native';

const App = () => {
  const FRUITS = [{ name: 'Banana', }, { name: 'Pineapple', }, { name: 'Strawberry', }];
  const [data, setData] = useState(FRUITS);

  const _addNew = () => {
    const dataCpy = [...data];
    dataCpy.push({ name: 'Another item', });
    setData(dataCpy);
  };

  const _onEdit = (edit, ind) => {
    const dataCpy = [...data];
    dataCpy[ind] = {name: edit};
    setData(dataCpy);
  };

  return (
    <SafeAreaView style={styles.container}>
      { data.map((item: any, ind: number) => <Item title={item.name} key={ind} index={ind} onEdit={_onEdit} />) }

      <Pressable style={styles.button} onPress={_addNew}>
        <Text style={styles.buttonTextLarge}> + Add new item</Text>
      </Pressable>
    </SafeAreaView>
  );
};

export default App;


const Item = ({ title, index, onEdit }: { title: string, index: number, onEdit: (edit: string, ind: number) => {} }) => {
  const [text, onTitleChanged] = useState(title);
  const [modalVisible, setModalVisible] = useState(false);

  // 同步父组件传来的title变化到本地状态
  useEffect(() => {
    onTitleChanged(title);
  }, [title]);

  const _toggleModal = () => {
    setModalVisible(!modalVisible);
  };

  const _onFinishEdit = () => {
    onEdit(text, index);
    _toggleModal();
  };

  return (<>
    <TouchableOpacity onPress={ _toggleModal }>
      <View style={styles.item}>
        <Text style={styles.title}>{title}</Text>
      </View>
    </TouchableOpacity>

    <Modal transparent={true} visible={modalVisible} onRequestClose={ _toggleModal }>
      <View style={styles.centeredView}>
        <View style={styles.modalView}>

          <TextInput
            style={styles.input}
            onChangeText={onTitleChanged}
            placeholder="useless placeholder"
            value={text}
          />

          <Pressable style={[styles.button, styles.buttonClose]} onPress={_onFinishEdit}>
            <Text style={styles.buttonText} >Finish edit</Text>
          </Pressable>

        </View>
      </View>
    </Modal>
  </>);

};


const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: StatusBar.currentHeight || 0,
    margin: 6,
  },
  item: {
    backgroundColor: '#00c2fe',
    padding: 12,
    borderRadius: 3,
    marginVertical: 8,
    marginHorizontal: 3,
  },
  title: {
    fontSize: 32,
  },
  input: {
    height: 40,
    margin: 12,
    borderWidth: 1,
    padding: 10,
  },
  centeredView: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    marginTop: 22,
  },
  modalView: {
    margin: 20,
    backgroundColor: 'white',
    borderRadius: 20,
    padding: 35,
    alignItems: 'center',
    shadowColor: '#000',
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.25,
    shadowRadius: 4,
    elevation: 5,
  },
  button: {
    borderRadius: 3,
    padding: 9,
    elevation: 2,
    marginTop: 15,
    backgroundColor: '#5bddb9',
  },
  buttonClose: {
    backgroundColor: '#2196F3',
  },
  buttonText: {
    fontSize: 12,
    fontWeight: "bold",
  },
  buttonTextLarge: {
    fontSize: 24,
    fontWeight: "bold",
  },
});

关键修复点

  • 传递正确索引:父组件map遍历给Item传递index={ind}属性,子组件接收index作为业务索引,不再误用key。
  • 同步父组件状态:子组件添加useEffect监听title props变化,实时更新本地text状态,确保父子组件数据一致。
  • 移除无效逻辑:删除初始化时自动触发的useEffect,仅保留完成编辑时手动调用onEdit的逻辑,避免初始状态被错误覆盖。

内容的提问来源于stack exchange,提问作者Monero Jeanniton

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 07:45:56