我有点困惑,可能没有正确使用 React Hooks,但我开始使用带有 React Hooks 的功能组件构建一个站点,我似乎在更新状态时遇到了问题。
所以我的困境是:
-
我从 API 检索一个项目数组并将其加载到钩子状态,然后将其映射到列表组中。
-
选择列表项时,onClick 事件会触发,我将所选项加载到另一个钩子中。 我最初将它放在一个钩子中,状态中嵌套了对象,但决定将其移动到自己的钩子中,以便我可以尝试更好地调试它。
-
每个输入的值都与第二个挂钩(所选项目挂钩(的状态相关联,并具有一个 onChange 函数,用于设置该特定挂钩的状态。 但是每当我开始在输入字段中键入时,原始列表数组都会在我键入时以某种方式更新。 似乎onChange函数也链接到原始状态/钩子。
我正在输入一些示例代码,但由于有很多内容要阅读,我删除了很多代码,但这是我尝试做的事情的基础。
const Terminal = props => { const [state, setState] = useState({
error: "",
searchResults: [],
showUploadModal: false,
termList: [{
_id: "",
code: "",
name: "",
accessorial: {
_id: "",
detention: 0,
chassispo: 0,
chassisstd: 0,
chassistri: 0,
hazardous: 0,
reefer: 0,
howland: 0,
liqour: 0,
stopoff: 0,
scale: 0,
storage: 0,
prepull: 0
},
active: true,
add_date: ""
}] });
let [selectedTerminal, setSelectedTerminal] = useState({
selectedTerm:{
name: "Test",
code: "Test",
accessorial: {
detention: 0,
chassispo: 0,
chassisstd: 0,
chassistri: 0,
hazardous: 0,
reefer: 0,
howland: 0,
liquor: 0,
stopoff: 0,
scale: 0,
storage: 0,
prepull: 0
},
active: false,
add_date: {} } })
useEffect(() => {
getTerminals();
setFirstTerminal(); }, []);
function getTerminals(){
applicationApi
.getTerminals()
.then(resp => {
setState({...state, termList: resp.terminals})
})
.catch(err => {
throw err;
}); }
function onTerminalChange(term) {
setSelectedTerminal({selectedTerm: term}); }
function onChange(event){
console.log(selectedTerminal);
var {selectedTerm} = selectedTerminal;
selectedTerm.name = event.target.value
console.log(selectedTerm);
setSelectedTerminal({selectedTerm: selectedTerm}); }
return (
<>
<Container fluid style={{position: "fixed", width: "100%"}}>
<Row noGutters>
<Col sm={2}>
<ListGroup className="termList">
{state.termList.map(term => {
return <ListGroup.Item action onClick={() => onTerminalChange(term)}>
{term.name}{" - "}{term.code}
</ListGroup.Item>;
})}
</ListGroup>
</Col>
<Col sm={6}>
<Tabs defaultActiveKey="main" id="uncontrolled-tab-example">
<Tab eventKey="main" title="Main">
<Form >
<Form.Row>
<Form.Group as={Col}>
<Form.Label>Name</Form.Label>
<Form.Control type="text" name="name" value={selectedTerminal.selectedTerm.name} onChange={(e) => onChange(e)}/>
</Form.Group>
<Form.Group as={Col}>
<Form.Label>Code</Form.Label>
{/* <Form.Control type="text" name="code" value={selectedTerminal.code}/> */}
</Form.Group>
</Form.Row>
</Col>
</Row>
</Container>
</> ); };
export default (Terminal)
这是一个具有类似问题的代码沙箱。 它只是在原始列表/状态中更改一次值,而不仅仅是更改另一个状态/钩子。
https://codesandbox.io/s/react-hook-issue-9rt83
似乎onChange函数也链接到原始状态/钩子。
是的。。。从技术上讲,它是对同一对象的引用...更改(突变(是在完全相同的一个对象上完成的......无论修改哪一个
要修复,您需要将所有源对象属性复制到新的属性中(如往常setState
( - 应该是复杂结构的深层克隆。
在这种情况下(2 个级别(,简单的修复就足够了:
function onTerminalChange(term) {
const newTerm = {...term}; // new main object
newTerm.accessorial = {...term.accessorial}; // new subobject
setSelectedTerminal({ selectedTerm: newTerm });
}
对于代码沙盒:
<li onClick={() => setTermState( {...term} )}>
我将使用选定的索引,而不是保存对象的状态。
import React, { useState } from "react";
import "./styles.css";
export default function App() {
let [state, setState] = useState({
termList: [
{ name: "Adele", code: "ade" },
{ name: "Agnes", code: "agn" },
{ name: "Billy", code: "bil" },
{ name: "Calvin", code: "cal" },
{ name: "Christina", code: "chr" },
{ name: "Cindy", code: "cin" }
]
});
let [termIndex, setTermIndex] = useState(0);
function onChangeName(event) {
setState({
termList: state.termList.map(term => ({
...term,
name:
event.target.defaultValue === term.name
? event.target.value
: term.name
}))
});
}
function onChangeCode(event) {
setState({
termList: state.termList.map(term => ({
...term,
code:
event.target.defaultValue === term.code
? event.target.value
: term.code
}))
});
}
return (
<div className="App">
<h2>
Click on any of the items to fill in inputs. Then type into inputs to
see issue.
</h2>
<input
name="name"
value={state.termList[termIndex].name}
onChange={onChangeName}
/>
<input
name="code"
value={state.termList[termIndex].code}
onChange={onChangeCode}
/>
<ul>
{state.termList.map((term, index) => {
return (
<li onClick={() => setTermIndex(index)}>
{term.name + " - " + term.code}
</li>
);
})}
</ul>
</div>
);
}
https://codesandbox.io/s/react-hook-issue-fvqsr?fontsize=14&hidenavigation=1&theme=dark