【发布时间】:2019-07-07 16:28:54
【问题描述】:
如何在 useState 数组 React 钩子中推送元素? 这是反应状态下的旧方法吗?还是新的东西?
【问题讨论】:
标签: javascript reactjs react-hooks
如何在 useState 数组 React 钩子中推送元素? 这是反应状态下的旧方法吗?还是新的东西?
【问题讨论】:
标签: javascript reactjs react-hooks
当你使用useState时,你可以获得状态项的更新方法:
const [theArray, setTheArray] = useState(initialArray);
然后,当您想要添加新元素时,您可以使用该函数并传入新数组或将创建新数组的函数。通常是后者,因为状态更新是异步的,有时是批处理的:
setTheArray(oldArray => [...oldArray, newElement]);
如果您仅为某些特定的用户事件(如click(但不像mousemove)更新处理程序中的数组,则有时您可以不使用该回调表单而侥幸逃脱:
setTheArray([...theArray, newElement]);
React 确保刷新渲染的事件是here 列出的“离散事件”。
实时示例(将回调传递给setTheArray):
const {useState, useCallback} = React;
function Example() {
const [theArray, setTheArray] = useState([]);
const addEntryClick = () => {
setTheArray(oldArray => [...oldArray, `Entry ${oldArray.length}`]);
};
return [
<input type="button" onClick={addEntryClick} value="Add" />,
<div>{theArray.map(entry =>
<div>{entry}</div>
)}
</div>
];
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
因为对theArray 的唯一更新是click 事件(“离散”事件之一)中的一个,所以我可以直接更新addEntry:
const {useState, useCallback} = React;
function Example() {
const [theArray, setTheArray] = useState([]);
const addEntryClick = () => {
setTheArray([...theArray, `Entry ${theArray.length}`]);
};
return [
<input type="button" onClick={addEntryClick} value="Add" />,
<div>{theArray.map(entry =>
<div>{entry}</div>
)}
</div>
];
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
【讨论】:
setTheArray(currentArray => [...currentArray, newElement])。最有可能在useEffect(...theArray..., []) 中,重要的是要意识到theArray 是一个常量,因此未来渲染的值需要functional updates
useEffect 例子...?
useEffect有一个空的依赖列表[],它只会在第一次渲染时执行。所以效果中theArray的值永远是initialArray。在setTheArray([...initialArray, newElement]) 没有意义的情况下,并且当theArray 常量将始终等于initialValue 时,则需要进行功能更新。
为了进一步扩展, 这里有一些常见的例子。开始于:
const [theArray, setTheArray] = useState(initialArray);
const [theObject, setTheObject] = useState(initialObject);
将元素推入数组末尾
setTheArray(prevArray => [...prevArray, newValue])
在对象末尾推送/更新元素
setTheObject(prevState => ({ ...prevState, currentOrNewKey: newValue}));
在对象数组的末尾推送/更新元素
setTheArray(prevState => [...prevState, {currentOrNewKey: newValue}]);
将元素推入数组对象的末尾
let specificArrayInObject = theObject.array.slice();
specificArrayInObject.push(newValue);
const newObj = { ...theObject, [event.target.name]: specificArrayInObject };
theObject(newObj);
这里还有一些工作示例。 https://codesandbox.io/s/reacthooks-push-r991u
【讨论】:
您可以在自定义状态的末尾附加数据数组:
const [vehicleData, setVehicleData] = React.useState<any[]>([]);
setVehicleData(old => [...old, ...newArrayData]);
例如,在下面,你出现了一个 axios 的例子:
useEffect(() => {
const fetchData = async () => {
const result = await axios(
{
url: `http://localhost:4000/api/vehicle?page=${page + 1}&pageSize=10`,
method: 'get',
}
);
setVehicleData(old => [...old, ...result.data.data]);
};
fetchData();
}, [page]);
【讨论】:
最推荐的方法是同时使用包装函数和展开运算符。例如,如果您像这样初始化了一个名为name 的状态,
const [names, setNames] = useState([])
你可以像这样推送到这个数组,
setNames(names => [...names, newName])
希望对您有所帮助。
【讨论】:
与 React 类组件中的“正常”状态相同。
示例:
function App() {
const [state, setState] = useState([]);
return (
<div>
<p>You clicked {state.join(" and ")}</p>
//destructuring
<button onClick={() => setState([...state, "again"])}>Click me</button>
//old way
<button onClick={() => setState(state.concat("again"))}>Click me</button>
</div>
);
}
【讨论】:
// Save search term state to React Hooks with spread operator and wrapper function
// Using .concat(), no wrapper function (not recommended)
setSearches(searches.concat(query))
// Using .concat(), wrapper function (recommended)
setSearches(searches => searches.concat(query))
// Spread operator, no wrapper function (not recommended)
setSearches([...searches, query])
// Spread operator, wrapper function (recommended)
setSearches(searches => [...searches, query])
https://medium.com/javascript-in-plain-english/how-to-add-to-an-array-in-react-state-3d08ddb2e1dc
【讨论】:
使用 useState() 创建一个数组状态 首先,让我们看看如何使用 useState() 钩子来创建数组状态变量。
import React from "react";
const { useState } = React;
const [myArray, setMyArray] = useState([]);
但是,在 React 中,我们需要使用从 useState 返回的方法来更新数组。
setMyArray(oldArray => [...oldArray, newElement]);
【讨论】:
setTheArray([...theArray, newElement]); 是最简单的答案,但要注意 theArray 中项目的变异。使用数组项的深度克隆。
【讨论】:
我尝试了上述方法将对象推送到 useState 中的对象数组中,但在使用 TypeScript 时出现以下错误:
键入'TxBacklog[] | undefined' 必须有一个返回 iterator.ts(2488) 的 'Symbol.iterator' 方法
tsconfig.json 的设置显然是正确的:
{
"compilerOptions": {
"target": "es6",
"lib": [
"dom",
"dom.iterable",
"esnext",
"es6",
],
此解决方法解决了问题(我的示例代码):
界面:
interface TxBacklog {
status: string,
txHash: string,
}
状态变量:
const [txBacklog, setTxBacklog] = React.useState<TxBacklog[]>();
将新对象推入数组:
// Define new object to be added
const newTx = {
txHash: '0x368eb7269eb88ba86..',
status: 'pending'
};
// Push new object into array
(txBacklog)
? setTxBacklog(prevState => [ ...prevState!, newTx ])
: setTxBacklog([newTx]);
【讨论】:
如果您想在特定索引之后推送,您可以执行以下操作:
const handleAddAfterIndex = index => {
setTheArray(oldItems => {
const copyItems = [...oldItems];
const finalItems = [];
for (let i = 0; i < copyItems.length; i += 1) {
if (i === index) {
finalItems.push(copyItems[i]);
finalItems.push(newItem);
} else {
finalItems.push(copyItems[i]);
}
}
return finalItems;
});
};
【讨论】: