ChatGPT解决这个技术问题 Extra ChatGPT

正确修改 React.js 中的状态数组

我想在 state 数组的末尾添加一个元素,这是正确的方法吗?

this.state.arrayvar.push(newelement);
this.setState({ arrayvar:this.state.arrayvar });

我担心使用 push 就地修改数组可能会导致麻烦 - 它安全吗?

制作数组副本的替代方法,setState这似乎很浪费。

我认为您可以使用反应不变性助手。看到这个:facebook.github.io/react/docs/update.html#simple-push
状态数组中的 setState 检查我的解决方案。<br/> <br> stackoverflow.com/a/59711447/9762736

i
isherwood

React docs 说:

将 this.state 视为不可变的。

您的 push 将直接改变状态,这可能会导致容易出错的代码,即使您之后再次“重置”状态也是如此。例如,它可能导致某些生命周期方法(如 componentDidUpdate)不会触发。

在更高版本的 React 版本中推荐的方法是在修改状态时使用更新函数来防止竞争条件:

this.setState(prevState => ({
  arrayvar: [...prevState.arrayvar, newelement]
}))

与使用非标准状态修改可能面临的错误相比,内存“浪费”不是问题。

早期 React 版本的替代语法

您可以使用 concat 获得干净的语法,因为它返回一个新数组:

this.setState({ 
  arrayvar: this.state.arrayvar.concat([newelement])
})

在 ES6 中,您可以使用 Spread Operator

this.setState({
  arrayvar: [...this.state.arrayvar, newelement]
})

您能否举例说明何时会出现竞态条件?
@Qiming push 返回新的数组长度,这样就行不通了。此外,setState 是异步的,React 可以将多个状态更改排队到单个渲染通道中。
@mindeavor 说您有一个在 this.state 中查找参数的 animationFrame,以及在状态更改时更改其他一些参数的另一种方法。可能存在状态已更改但未反映在侦听更改的方法中的某些帧,因为 setState 是异步的。
@ChristopherCamps 这个答案不鼓励调用 setState 两次,它显示了两个类似的设置状态数组而不直接改变它的例子。
如今,将状态数组视为不可变的一种简单方法是:let list = Array.from(this.state.list); list.push('woo'); this.setState({list});当然要根据您的样式偏好进行修改。
D
David Hellsing

最简单,如果您使用 ES6

initialArray = [1, 2, 3];

newArray = [ ...initialArray, 4 ]; // --> [1,2,3,4]

新数组将为 [1,2,3,4]

在 React 中更新你的状态

this.setState({
  arrayvar:[...this.state.arrayvar, newelement]
});

Learn more about array destructuring


追加或前置非常简单。搜索和替换呢?例如对象数组。我需要更新一个按 id 搜索的对象?
您的问题不直接涉及 OP 问题
@ChanceSmith: StateLess 答案也需要它。不要依赖于状态本身的状态更新。官方文档:reactjs.org/docs/…
@Sisir 和任何想知道 how to update an object within an array in the state 的人。
@RayCoder 记录并检查 arrayvar 的值,看起来它不是数组。
D
David Hellsing

ES6 最简单的方法:

this.setState(prevState => ({
    array: [...prevState.array, newElement]
}))

抱歉,在我的情况下,我想将一个数组推入数组。 tableData = [['test','test']] 推送我的新数组 tableData = [['test','test'],['new','new']] 后。如何推动这个@David 和@Ridd
@Johncy 如果您想获得 [['test','test'],['new','new']],请尝试:this.setState({ tableData: [...this.state.tableData, ['new', 'new']]
this.setState({ tableData: [...this.state.tableData ,[item.student_name,item.homework_status_name,item.comments===null?'-':item.comments] ] }); 它两次插入新数组 this.state.tableData.push([item.student_name,item.homework_status_name,item.comments===null?'-':item.comments]); 它实现了我想要的东西。但它不是我认为的正确方式。
N
NealeU

React 可能会批量更新,因此正确的方法是为 setState 提供一个执行更新的函数。

对于 React 更新插件,以下内容将可靠地工作:

this.setState( state => update(state, {array: {$push: [4]}}) );

或者对于 concat():

this.setState( state => ({
    array: state.array.concat([4])
}));

下面以 https://jsbin.com/mofekakuqi/7/edit?js,output 为例说明如果你弄错了会发生什么。

setTimeout() 调用正确地添加了三个项目,因为 React 不会在 setTimeout 回调中批量更新(请参阅 https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ)。

有问题的 onClick 只会添加“第三”,但固定的会按预期添加 F、S 和 T。

class List extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      array: []
    }

    setTimeout(this.addSome, 500);
  }

  addSome = () => {
      this.setState(
        update(this.state, {array: {$push: ["First"]}}));
      this.setState(
        update(this.state, {array: {$push: ["Second"]}}));
      this.setState(
        update(this.state, {array: {$push: ["Third"]}}));
    };

  addSomeFixed = () => {
      this.setState( state => 
        update(state, {array: {$push: ["F"]}}));
      this.setState( state => 
        update(state, {array: {$push: ["S"]}}));
      this.setState( state => 
        update(state, {array: {$push: ["T"]}}));
    };



  render() {

    const list = this.state.array.map((item, i) => {
      return <li key={i}>{item}</li>
    });
       console.log(this.state);

    return (
      <div className='list'>
        <button onClick={this.addSome}>add three</button>
        <button onClick={this.addSomeFixed}>add three (fixed)</button>
        <ul>
        {list}
        </ul>
      </div>
    );
  }
};


ReactDOM.render(<List />, document.getElementById('app'));

真的有这种情况发生吗?如果我们简单地做 this.setState( update(this.state, {array: {$push: ["First", "Second", "Third"]}}) )
@Albizia 我认为您应该找一位同事并与他们讨论。如果您只进行一次 setState 调用,则不存在批处理问题。重点是为了说明 React 是批量更新的,所以是的……确实有一个案例,就是上面代码的 JSBin 版本中可以找到的。这个线程中的几乎所有答案都无法解决这个问题,所以会有很多代码有时会出错
state.array = state.array.concat([4]) 这会改变先前的状态对象。
@EmileBergeron 感谢您的坚持。我最终回头看看我的大脑拒绝看到什么,并检查了文档,所以我会编辑。
好的!很容易出错,因为 JS 中的不变性并不明显(在处理库的 API 时更是如此)。
c
coderpc

如果你在 React 中使用函数式组件

const [cars, setCars] = useState([{
  name: 'Audi',
  type: 'sedan'
}, {
  name: 'BMW',
  type: 'sedan'
}])

...

const newCar = {
  name: 'Benz',
  type: 'sedan'
}

const updatedCarsArray = [...cars, newCar];

setCars(updatedCarsArray);

C
Clarkie

正如评论中提到的@nilgun,您可以使用react immutability helpers。我发现这非常有用。

从文档:

简单推送

var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]

initialArray 仍然是 [1, 2, 3]。


React 不变性助手在文档中被描述为已弃用。现在应该改用 github.com/kolodny/immutability-helper
这个答案和这个评论是真实的,我很感激花时间以如此简洁的方式来写它——你们俩。 immutability-helper 表达了这种担忧,并且在这个方向上有很多想法和代码。
m
moshfiqrony

目前有很多人面临更新 useState 挂钩状态的问题。我使用这种方法安全地更新它并想在这里分享它。

这是我的状态

const [state, setState] = useState([])

假设我有一个对象名称 obj1,并且我希望它附加到我的状态中。我会建议这样做

setState(prevState => [...prevState, obj1])

这将在最后安全地插入对象并保持状态一致性


当新值依赖于前一个状态时,这是更新状态的正确方法。文档:如果下一个状态依赖于当前状态,我们建议使用更新函数形式: setState((state) => ...,参见en.reactjs.org/docs/react-component.html#setstate -- 状态更新不会立即发生,所以在使用原始状态时变量,某些更新可能会被新的更新覆盖。
H
Harshan Morawaka

如果您正在使用功能组件,请按如下方式使用。

const [chatHistory, setChatHistory] = useState([]); // define the state

const chatHistoryList = [...chatHistory, {'from':'me', 'message':e.target.value}]; // new array need to update
setChatHistory(chatHistoryList); // update the state

伙计,我挣扎了 12 个小时不知道发生了什么事,你救了我的命
@HiệpNguyễn 不错
U
U12-Forward

对于向数组中添加新元素,push() 应该是答案。

对于数组的删除元素和更新状态,下面的代码适用于我。 splice(index, 1) 无法工作。

const [arrayState, setArrayState] = React.useState<any[]>([]);
...

// index is the index for the element you want to remove
const newArrayState = arrayState.filter((value, theIndex) => {return index !== theIndex});
setArrayState(newArrayState);

I
Ian Smith

这是一个 2020 年的 Reactjs Hook 示例,我认为它可以帮助其他人。我正在使用它向 Reactjs 表添加新行。让我知道我是否可以改进一些东西。

向功能状态组件添加新元素:

定义状态数据:

    const [data, setData] = useState([
        { id: 1, name: 'John', age: 16 },
        { id: 2, name: 'Jane', age: 22 },
        { id: 3, name: 'Josh', age: 21 }
    ]);

有一个按钮触发一个添加新元素的功能

<Button
    // pass the current state data to the handleAdd function so we can append to it.
    onClick={() => handleAdd(data)}>
    Add a row
</Button>
function handleAdd(currentData) {

        // return last data array element
        let lastDataObject = currentTableData[currentTableData.length - 1]

        // assign last elements ID to a variable.
        let lastID = Object.values(lastDataObject)[0] 

        // build a new element with a new ID based off the last element in the array
        let newDataElement = {
            id: lastID + 1,
            name: 'Jill',
            age: 55,
        }

        // build a new state object 
        const newStateData = [...currentData, newDataElement ]

        // update the state
        setData(newStateData);

        // print newly updated state
        for (const element of newStateData) {
            console.log('New Data: ' + Object.values(element).join(', '))
        }

}

如果我不想添加,而是想从数组中删除一个元素怎么办?
@Ken 您正在使用哪种数组?你的数组对象应该有一个内置的删除函数。你会触发删除,然后更新状态。
M
MD SHAYON

由于不允许直接改变状态,因此不能简单地将项目推送到数组。

state = {
      value: '',
      list: ['a', 'b', 'c'],
    };

this.setState({
  list: [...this.state.list, newelement]
})


//or

  onAddItem = () => {
    // not allowed AND not working
    this.setState(state => {
      const list = state.list.push(state.value);
 
      return {
        list,
        value: '',
      };
    });
  };

know more


在第二个语句中,您将丢失“值”键。您应该做的只是更新保持上一个状态的列表: setState({...state, list: [...state.list, newelement]})
k
kyun
this.setState(preState=>({arrayvar:[...prevState.arrayvar,newelement]}))

这将解决这个问题。


m
meiser

我所做的是更新状态之外的值并执行 forceupdate(),反应管理的内容越少越好,因为您可以更好地控制更新的内容。如果更新速度很快,还为每次更新创建一个新数组可能会太昂贵


包含 minimal, reproducible example 可以改进您的答案。
R
Rajnikant Lodhi

我正在尝试在数组状态中推送值并像这样设置值,并通过映射函数定义状态数组和推送值。

 this.state = {
        createJob: [],
        totalAmount:Number=0
    }


 your_API_JSON_Array.map((_) => {
                this.setState({totalAmount:this.state.totalAmount += _.your_API_JSON.price})
                this.state.createJob.push({ id: _._id, price: _.your_API_JSON.price })
                return this.setState({createJob: this.state.createJob})
            })

A
Andrzej Sydor

当我想修改数组状态同时保留数组中元素的位置时,我遇到了类似的问题

这是一个在喜欢和不喜欢之间切换的功能:

    const liker = (index) =>
        setData((prevState) => {
            prevState[index].like = !prevState[index].like;
            return [...prevState];
        });

正如我们可以说的那样,该函数获取数组状态中元素的索引,然后我们继续修改旧状态并重建状态树


这是在改变之前的状态,这是 React 中的反模式。
@EmileBergeron 我们如何在不破坏反应规则的情况下修改状态中的元素同时保留位置?
F
Fernando Alcantara
//get the value you want to add
const valor1 = event.target.elements.valor1.value;

//add in object 
        const todo = {
            valor1,
        }

//now you just push the new value into the state

//prevlista is the value of the old array before updating, it takes the old array value makes a copy and adds a new value

setValor(prevLista =>{
return prevLista.concat(todo) })
     

M
MadKad

这对我来说可以在数组中添加一个数组

this.setState(prevState => ({
    component: prevState.component.concat(new Array(['new', 'new']))
}));

M
Mesut Akcan
//------------------code is return in typescript 

const updateMyData1 = (rowIndex:any, columnId:any, value:any) => {

    setItems(old => old.map((row, index) => {
        if (index === rowIndex) {
        return Object.assign(Object.assign({}, old[rowIndex]), { [columnId]: value });
    }
    return row;
}));

H
Hamid Hosseinpour

这段代码对我有用:

fetch('http://localhost:8080')
  .then(response => response.json())
  .then(json => {
    this.setState({mystate: this.state.mystate.push.apply(this.state.mystate, json)})
  })

仍然,你直接改变状态
并且自 .push returns a number 以来未能正确更新组件的状态,而不是数组。