英文:
How to save data from different children to a single array in parent component
问题
以下是您要翻译的内容:
"我有三个组件。每当我在任何子组件(First
和Second
)中点击按钮时,父组件(Test
)应该显示输入到子组件的文本。问题是,每当我点击其他子组件的按钮时,都会创建一个新数组,其中包含来自该特定组件的数据。
以下是代码:
Test 组件:
function Test() {
const [ChildData, setChildData] = useState('');
console.log(ChildData)
return (
<div>
<h1>Test</h1>
<div>
{ChildData ? <div>{ChildData.map((data) => { return <div>{data}</div> })}</div> : null}
</div>
<First passChildData={setChildData} />
<Second passChildData={setChildData} />
</div>
)
}
First 组件:
function First(props) {
const [Data, setData] = useState('');
const [Items, setItems] = useState('')
const handlechange = (e) => {
setData(e.target.value)
}
const handleClick = () => {
if (Data !== '') {
setItems((prevData) => {
const newData = [...prevData, Data];
props.passChildData(newData)
return newData
})
setData('')
} else {
console.log("请输入一些内容")
}
}
return (
<div>
<h1>First</h1>
<input type="text" onChange={handlechange} value={Data} />
<button onClick={handleClick}>添加</button>
{Data}
<div>{Items ? <div>{Items.map((item) => { return <div>{item}</div> })}</div> : null }</div>
</div>
)
}
Second 组件:
function Second(props) {
const [Data, setData] = useState('');
const [Items, setItems] = useState('')
const handlechange = (e) => {
setData(e.target.value)
}
const handleClick = () => {
if (Data !== '') {
setItems((prevData) => {
const newData = [...prevData, Data];
props.passChildData(newData)
return newData
})
setData('')
} else {
console.log("请输入一些内容")
}
}
return (
<div>
<h1>Second</h1>
<input type="text" onChange={handlechange} value={Data} />
<button onClick={handleClick}>添加</button>
{Data}
<div>{Items ? <div>{Items.map((item) => { return <div>{item}</div> })}</div> : null }</div>
</div>
)
}
我期望的是:
- 当我在
First
组件中输入“什么”; - 然后在
Second
组件中输入“是”; - 然后在
First
组件中输入“你的”; - 然后在
Second
组件中输入“名字?”
我希望在父组件(Test
)内显示“什么是你的名字?”(不管它是否在不同的div或行中;我希望每个项目都按输入的顺序显示)。"
英文:
Here I have three components. Whenever I click the button in any of the child components (First
and Second
) the parent (Test
) component should display text entered into the child component. The problem is that whenever I click the button of other child component a new array is created with data from that particular component.
Here's the code:
Test component:
function Test() {
const [ChildData , setChildData] = useState('');
console.log(ChildData)
return (
<div>
<h1>Test</h1>
<div>
{ChildData? <div>{ChildData.map((data)=>{return <div>{data}</div> })}</div>:null }
</div>
<First passChildData={setChildData}/>
<Second passChildData={setChildData}/>
</div>
)
}
First component:
function First(props) {
const [Data, setData] = useState('');
const [Items, setItems] = useState('')
const handlechange = (e)=>{
setData(e.target.value)
}
const handleClick = ()=>{
if(Data != ''){
setItems((prevData)=>{
const newData = [...prevData,Data];
props.passChildData(newData)
return newData
})
setData('')
}else{
console.log("enter something")
}
}
return (
<div>
<h1>First</h1>
<input type="text" onChange={handlechange} value={Data}/>
<button onClick={handleClick}>Add</button>
{Data}
<div>{Items? <div>{Items.map((item)=>{return <div>{item}</div> })}</div>:null }</div>
</div>
)
}
Second component:
function Second(props) {
const [Data, setData] = useState('');
const [Items, setItems] = useState('')
const handlechange = (e)=>{
setData(e.target.value)
}
const handleClick = ()=>{
if(Data != ''){
setItems((prevData)=>{
const newData = [...prevData,Data];
props.passChildData(newData)
return newData
})
setData('')
}else{
console.log("enter something")
}
}
return (
<div>
<h1>Second</h1>
<input type="text" onChange={handlechange} value={Data}/>
<button onClick={handleClick}>Add</button>
{Data}
<div>{Items? <div>{Items.map((item)=>{return <div>{item}</div> })}</div>:null }</div>
</div>
)
}
What I expect is:
- When I enter "What" into the
First
component; - Then "is" into the
Second
component; - Then "your" into the
First
component - Then "name?" in
Second
component
I want "What is your name?" (Doesn't matter if it's in different divs or lines; I want every single item to be displayed in the order it was entered) to be shown inside the parent (Test
) component.
答案1
得分: 1
首先,我不会有两个几乎相同的组件 - First
和 Second
- 除了它们的标题之外,我会有一个带有 heading
作为属性的单一组件。
其次,我会使用一个带有 onSubmit
处理程序的 <form>
,而不是一个带有 onClick
处理程序的 <button>
,因为这样用户可以通过在输入字段具有焦点时按下 [Enter] 键来添加项目,例如。
第三,我会使用 useEffect
钩子来监听对 First
组件到 Items
数组的更改,然后在有更改时调用 passChildData
属性函数。请注意,用于引用数组的变量应该用空数组初始化,例如:const [Items, setItems] = useState([])
。
最终的代码如下:
英文:
First, I would not have two components - First
and Second
- that are nearly identical except for their headings; I would have a single component with heading
as a prop.
Second, I would use a <form>
with an onSubmit
handler instead of a <button>
with an onClick
handler because this will allow the user to add an item by, for example, pressing [Enter] while the input field has focus.
Third, I would use the useEffect
hook to listen for changes in the First
component to the Items
array and then call the passChildData
prop function when there is a change. Note that variables that are to reference arrays should be initialized with empty arrays, for example: const [Items, setItems] = useState([])
.
The final code looks like:
function Test() {
const [ChildData, setChildData] = useState([]);
const setItem = (newItem) => {
setChildData([...ChildData, newItem]);
}
return (
<div>
<h1>Test</h1>
<div>
{ChildData.map((data, index) => <div key={index}>{data}</div>)}
</div>
<First heading="First" passChildData={setItem}/>
<First heading="Second" passChildData={setItem}/>
</div>
)
}
function First(props) {
const [Data, setData] = useState('');
const [Items, setItems] = useState([])
useEffect(() => {
props.passChildData(Data);
}, [Items])
const handlechange = (e)=>{
setData(e.target.value)
}
const handleSubmit = (e) => {
e.preventDefault();
if (Data === '') {
console.log('enter something');
} else {
setItems([...Items, Data]);
}
}
return (
<div>
<h1>{props.heading}</h1>
<form onSubmit={handleSubmit}>
<input type="text" onChange={handlechange} value={Data}/>
<button type="submit">Add</button>
{Data}
</form>
<div>
{Items.map((item, index) => <div key={index}>{item}</div>)}
</div>
</div>
)
}
I have created a fiddle for reference.
答案2
得分: 0
问题在于你在每个组件内部都对整个状态进行了变更。换句话说,你没有使用prevData
。
我建议在First
和Second
组件的onClick
方法中更改状态,就像这样:
setItems((prevData) => {
const newData = [***...prevData***, ...Items, Data];
props.passChildData(newData);
return newData;
})
英文:
The problem is that you are mutating the whole state within every component. In other words, you don't use prevData
.
I would change the state in onClick
method of First and Second component, like this:
setItems((prevData)=>{
const newData = [***...prevData***, ...Items,Data];
props.passChildData(newData)
return newData
})
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论