ReactJS Array.push 函数在 setState 中不起作用
Posted
技术标签:
【中文标题】ReactJS Array.push 函数在 setState 中不起作用【英文标题】:ReactJS Array.push function not working in setState 【发布时间】:2017-04-24 11:17:38 【问题描述】:到目前为止,我正在制作一个包含 3 个问题的原始测验应用程序,所有问题都是对或错。在我的handleContinue
方法中,调用了将用户输入从无线电表单推送到userAnswers
数组中。第一次运行handleContinue
运行良好,之后会抛出错误:Uncaught TypeError: this.state.userAnswers.push is not a function(…)
import React from "react"
export default class Questions extends React.Component
constructor(props)
super(props)
this.state =
questionNumber: 1,
userAnswers: [],
value: ''
this.handleContinue = this.handleContinue.bind(this)
this.handleChange = this.handleChange.bind(this)
//when Continue button is clicked
handleContinue()
this.setState(
//this push function throws error on 2nd go round
userAnswers: this.state.userAnswers.push(this.state.value),
questionNumber: this.state.questionNumber + 1
//callback function for synchronicity
, () =>
if (this.state.questionNumber > 3)
this.props.changeHeader(this.state.userAnswers.toString())
this.props.unMount()
else
this.props.changeHeader("Question " + this.state.questionNumber)
)
console.log(this.state.userAnswers)
handleChange(event)
this.setState(
value: event.target.value
)
render()
const questions = [
"Blargh?",
"blah blah blah?",
"how many dogs?"
]
return (
<div class="container-fluid text-center">
<h1>questions[this.state.questionNumber - 1]</h1>
<div class="radio">
<label class="radio-inline">
<input type="radio" class="form-control" name="trueFalse" value="true"
onChange=this.handleChange/>True
</label><br/><br/>
<label class="radio-inline">
<input type="radio" class="form-control" name="trueFalse" value="false"
onChange=this.handleChange/>False
</label>
<hr/>
<button type="button" class="btn btn-primary"
onClick=this.handleContinue>Continue</button>
</div>
</div>
)
【问题讨论】:
【参考方案1】:Array.push 不返回新数组。尝试使用
this.state.userAnswers.concat([this.state.value])
这将返回新的 userAnswers 数组
参考:array push 和 array concat
【讨论】:
这个答案解决了问题,但并没有真正解释发生了什么。我建议查看我的答案,该答案更详细地解释了该问题。【参考方案2】:您应该将状态对象视为不可变对象,但是您需要重新创建数组以使其指向新对象,设置新项目,然后重置状态。
handleContinue()
var newState = this.state.userAnswers.slice();
newState.push(this.state.value);
this.setState(
//this push function throws error on 2nd go round
userAnswers: newState,
questionNumber: this.state.questionNumber + 1
//callback function for synchronicity
, () =>
if (this.state.questionNumber > 3)
this.props.changeHeader(this.state.userAnswers.toString())
this.props.unMount()
else
this.props.changeHeader("Question " + this.state.questionNumber)
)
console.log(this.state.userAnswers)
上述解决方案的另一种选择是使用.concat()
,因为它本身会返回一个新数组。它相当于创建一个新变量,但代码要短得多。
this.setState(
userAnswers: this.state.userAnswers.concat(this.state.value),
questionNumber: this.state.questionNumber + 1
【讨论】:
这很好用,但每次运行handleContinue
时都声明一个新变量似乎不是最佳选择。虽然我可能是错的,但想法?
你是对的,它确实会浪费内存,但它比直接改变状态可能出现的潜在竞争条件要好
这不是一个很好的答案。虽然它在技术上有效,但仅使用 concat
会更短更清晰,the docs 建议这样做。
这并不总是正常工作。我只是遇到了一个问题,即相同的方法在一个组件中起作用,而在另一个具有相同道具的组件上不起作用。最好改用concat
。【参考方案3】:
Do not modify state directly!一般情况下试试avoid mutation。
Array.prototype.push()
就地改变数组。所以本质上,当你 push
到 setState
中的一个数组时,你使用 push
改变了原始状态。由于push
返回的是新数组长度而不是实际数组,因此您将this.state.userAnswers
设置为一个数值,这就是为什么您在第二次运行时得到Uncaught TypeError: this.state.userAnswers.push is not a function(…)
,因为您不能@ 987654331@到一个号码。
您需要改用Array.prototype.concat()。它不会改变原始数组,而是返回一个包含新连接元素的新数组。这就是您想要在setState
中执行的操作。您的代码应如下所示:
this.setState(
userAnswers: this.state.userAnswers.concat(this.state.value),
questionNumber: this.state.questionNumber + 1
【讨论】:
【参考方案4】:我找到了解决办法。这也适用于 splice 和其他人。假设我有一个状态是一系列汽车:
this.state =
cars: ['BMW','AUDI','mercedes']
;
this.addState = this.addState.bind(this);
现在,addState 是我将用来向我的数组添加新项目的方法。这应该是这样的:
addState()
let arr = this.state.cars;
arr.push('skoda');
this.setState(cars: arr);
感谢 duwalanise,我找到了这个解决方案。我所要做的就是返回新数组以推送新项目。我很长一段时间都面临着这种问题。我会尝试更多的功能,看看它是否真的适用于所有通常不会的功能。如果有人对如何使用更简洁的代码实现这一点有更好的想法,请随时回复我的帖子。
【讨论】:
【参考方案5】:在以后的 React 版本中推荐的方法是在修改状态时使用更新器函数来防止竞争条件:
this.setState(prevState => (
userAnswers: [...prevState.userAnswers, this.state.value]
));
【讨论】:
【参考方案6】:当你想向它推送一些东西时,改变你的状态的正确方法是执行以下操作。假设我们已经定义了一个状态:
const [state, setState] = useState([])
现在我们要将以下对象推入状态数组。我们使用 concat 方法来实现这个操作:
let object = a: '1', b:'2', c:'3'
现在要将这个对象推入状态数组,请执行以下操作:
setState(state => state.concat(object))
您将看到您的状态填充了该对象。 concat 有效而 push 无效的原因如下
Array.prototype.push() adds an element into original array and returns an integer which is its new array length.
Array.prototype.concat() returns a new array with concatenated element without even touching in original array. It's a shallow copy.
【讨论】:
以上是关于ReactJS Array.push 函数在 setState 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
array.push 不是一个函数 - 当使用 reduce [重复]
Javascript - 为啥从函数返回 array.push(x) 不会将元素 x 推送到数组中?
当结构有两个以上参数时,带有 array.push() 的 Solidity 函数不起作用