由子组件管理的React状态和事件



子组件使用回调函数管理父对象的状态。代码破解只适用于一个变量,但在处理对象时会出错。我得到的错误是在文本区域输入值。。

remaks.map不是函数

请帮我解决这个问题。

此外,请告诉我这里的参考是否有任何用处。非常感谢。


return (
<div className="container">
{remarks?.map((items: any) => {
return (
<div key={items?.id}>
<label>
<textarea
name="remarkVal"
id={items?.id}
onChange={(e) => onSliderChangeHandler(e)}
value={items?.remarksVal}
ref={childRef}
placeholder={placeholder}
/>
</label>
</div>
);
})}
</div>
);
};

在根据答案编辑代码时获取新行。

setChildState((prevState: any) => [
...prevState,
{ [e.target.name]: e.target.value }
]);

您的状态值是一个数组:

const [remarks, setRemarks] = useState( [{ id: 1, remarkVal: "hello man" }]);

当您在这里更新状态时,您将其更改为对象:

setChildState((prevState: any) => ({
...prevState,
[e.target.name]: e.target.value
}));

正如错误所述,map()不是对象上的函数。将状态值保持为数组。例如,您可以向其附加一个元素:

setChildState((prevState: any) => ([
...prevState,
e.target.value
]));

或者修改(替换(数组中的单个项:

setChildState((prevState: any) => ([{
...prevState[0],
[e.target.name]: e.target.value
}]));

(注意:这个假设数组总是只有一个项。尽管你似乎无论如何都在做这个假设。维护一个只有一个项目的数组是很奇怪的。(

或者数组将包含多个项目,并且您想更新一个特定的项目?你在onSliderChangeHandler中奇怪地使用.map()可能是在暗示这一点。在这种情况下,你可能想要这样的东西:

const onSliderChangeHandler = (e: any) => {
setChildState((prevState: any) => ([
...prevState.map(p => {
if (p.id === e.target.id) {
return { ...p, [e.target.name]: e.target.value };
} else {
return p;
}
});
]));
};

请注意,如何将状态更新到映射操作的结果数组,而不是在数组上映射到仅一个项的更新状态,其中目标项被替换(所有其他项按原样返回(。


基本上,您需要做的是后退一步,检查/理解您正在使用的数据结构。它应该是一个对象还是一组对象?为什么?当进行更新时,应该更改什么?为什么?不要只是对";让它工作";,有意维护要维护的数据。

作者:Konrad Linkowski链接:https://codesandbox.io/s/relaxed-fog-8nfnhb?file=/src/App.js

export default function App() {
const [Form, setForm] = useState(Details);
const [remarks, setRemarks] = useState([{ id: 1, remarksVal: "hello man" }]);
const [parentState, setParentState] = useState(123);
// make wrapper function to give child
const wrapperSetParentState = useCallback(
(val) => {
setParentState(val);
},
[setParentState]
);
const setterRemarks = useCallback(
(val) => {
setRemarks(val);
},
[setRemarks]
);
useEffect(() => {
console.log("parent", remarks);
}, [remarks]);
return (
<div className="App">
<RemarksPage
remarks={remarks}
setterRemarks={setterRemarks}
placeholder="I am remarks section..."
/>
<div style={{ margin: 30 }}>
<Child
parentState={parentState}
parentStateSetter={wrapperSetParentState}
/>
<br />
{parentState}
</div>
</div>
);
}
import { Key, useEffect, useRef, useState } from "react";
export default ({ remarks, placeholder, setterRemarks, ...rest }) => {
const childRef = useRef();
const [childState, setChildState] = useState(remarks);
useEffect(() => {
setterRemarks(childState);
}, [setterRemarks, childState]);
const onSliderChangeHandler = (id: Key | null | undefined, value: string) => {
setChildState((remarks: any[]) =>
remarks.map((remark) =>
remark.id === id ? { ...remark, remarksVal: value } : remark
)
);
};
return (
<div className="container">
{remarks?.map(
(items: {
id: Key | null | undefined;
remarksVal: string | number | readonly string[] | undefined;
}) => {
return (
<div key={items?.id}>
<label>
<textarea
name="remarkVal"
id={items?.id}
onChange={(e) =>
onSliderChangeHandler(items.id, e.target.value)
}
value={items?.remarksVal}
ref={childRef}
placeholder={placeholder}
/>
</label>
</div>
);
}
)}
</div>
);
};

最新更新