在ReactJS中正确修改状态数组

时间:2014-10-08 09:20:37

标签: javascript reactjs

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

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

我担心使用push就地修改数组可能会造成麻烦 - 是否安全?

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

16 个答案:

答案 0 :(得分:619)

React docs说:

  

将this.state视为不可变。

您的push将直接改变状态,这可能会导致容易出错的代码,即使您正在重置"之后又是国家。 F.ex,它可能导致像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]
})

答案 1 :(得分:116)

最简单,如果您使用的是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

答案 2 :(得分:50)

使用ES6的最简单方法:

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

答案 3 :(得分:21)

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

对于React update addon,以下内容将可靠地运行:

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

或对于concat():

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

以下显示了https://jsbin.com/mofekakuqi/7/edit?js,output作为错误时会发生什么的示例。

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

有缺陷的onClick只会添加“Third”,但是固定的,会按预期添加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'));

答案 4 :(得分:17)

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

来自文档:

简单推送

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

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

答案 5 :(得分:8)

如果您在 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);

答案 6 :(得分:4)

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

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

答案 7 :(得分:2)

要将新元素添加到数组中,应使用push()

对于remove元素和array的更新状态,下面的代码对我有用。 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);

答案 8 :(得分:0)

这是我认为可以帮助他人的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(', '))
        }

}

答案 9 :(得分:0)

选项一正在使用

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

选项2:

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

答案 10 :(得分:-1)

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

答案 11 :(得分:-1)

我试图以数组状态推送值并像这样设置值,并通过map函数定义状态数组并推送值。

select c.name,
       c.mobile,
       group_concat(o.Product) #products name separated by a comma
from customers c
left join orders o on
  c.id = o.customer_id
group by c.id

答案 12 :(得分:-1)

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

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

答案 13 :(得分:-1)

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

此功能可在喜欢和不喜欢之间切换:

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

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

答案 14 :(得分:-2)

//------------------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;
}));

答案 15 :(得分:-4)

此代码对我有用:

marker.addListener('mouseover', function() {
    infowindow.open(map, marker);
  });

marker.addListener('mouseout', function() {
  infowindow.close();
});