ReactJS에서 상태 배열의 올바른 수정


416

state배열 끝에 요소를 추가하고 싶습니다 . 올바른 방법입니까?

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

대신 배열을 수정 push하면 문제가 발생할 수 있다는 것이 우려됩니다. 안전합니까?

어레이의 사본을 만들고 setStateing을 낭비하는 대안 .


9
반응 불변 도우미를 사용할 수 있다고 생각합니다. 이것을보십시오 : facebook.github.io/react/docs/update.html#simple-push
nilgun

상태 배열의 setState가 내 솔루션을 확인하십시오. <br/> <br> stackoverflow.com/a/59711447/9762736
Rajnikant Lodhi

답변:


763

문서 반응 말합니다 :

이 상태를 불변 인 것처럼 취급하십시오.

귀하는 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]
})

8
경쟁 조건이 발생하는 예를 제공 할 수 있습니까?
soundly_typed

3
@Qiming push은 새로운 배열 길이를 반환하므로 작동하지 않습니다. 또한 setState비동기이며 React는 여러 상태 변경을 단일 렌더 패스에 대기시킬 수 있습니다.
David Hellsing

2
@mindeavor는 this.state에서 매개 변수를 찾는 animationFrame과 상태 변경시 다른 매개 변수를 변경하는 다른 메소드가 있다고 말합니다. setState가 비동기이기 때문에 상태가 변경되었지만 변경을 수신하는 메소드에 반영되지 않는 일부 프레임이있을 수 있습니다.
David Hellsing

1
@ChristopherCamps이 답변은 setState두 번 호출하는 것을 권장하지 않으며 직접 배열을 변경하지 않고 상태 배열을 설정하는 두 가지 유사한 예를 보여줍니다.
David Hellsing

2
요즘 상태 배열을 변경할 수없는 쉬운 방법은 다음과 같습니다 let list = Array.from(this.state.list); list.push('woo'); this.setState({list});. 물론 스타일 기본 설정을 수정하십시오.
basicdays

133

를 사용하는 경우 가장 쉽습니다 ES6.

initialArray = [1, 2, 3];

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

새로운 배열은 [1,2,3,4]

React 에서 상태를 업데이트하려면

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

배열 파괴에 대해 더 알아보기


@Muzietto 당신은 정교한 수 있습니까?
StateLess

4
이 질문의 핵심은 배열을 수정하지 않고 반응 상태를 변경하는 것입니다. 당신은 내 요점을 직접보고 답을 편집했습니다. 이것은 당신의 대답과 관련이 있습니다. 잘 했어.
Marco Faustinelli

2
귀하의 질문은 OP 질문과 직접 ​​관련이 없습니다
StateLess

1
@ChanceSmith : StateLess 에서도 필요합니다 . 상태 자체는 상태 업데이트에 의존하지 마십시오. 공식 문서 : reactjs.org/docs/…
arcol

1
@RayCoder 로그 및 arrayvar의 값을 확인하십시오. 배열이 아닌 것처럼 보입니다.
StateLess

57

가장 간단한 방법 ES6:

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

죄송합니다. 제 경우에는 배열을 배열로 푸시하고 싶습니다. tableData = [['test','test']]내 새 배열을 푸시 한 후 tableData = [['test','test'],['new','new']]. @David와 @Ridd를 푸시하는 방법
Johncy

@Johncy 당신이 [['test','test'],['new','new']]시도하고 싶다면 :this.setState({ tableData: [...this.state.tableData, ['new', 'new']]
Ridd

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]);. 원하는 것을 달성합니다. 그러나 내가 생각하는 올바른 방법은 아닙니다.
Johncy

26

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 , 출력이 잘못되었을 경우 발생하는 결과의 예입니다.

React가 setTimeout 콜백 내에서 업데이트를 일괄 처리하지 않기 때문에 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'));

실제로 발생하는 경우가 있습니까? 우리가 단순히한다면this.setState( update(this.state, {array: {$push: ["First", "Second", "Third"]}}) )
Albizia

1
@Albizia 동료를 찾아 그들과상의해야한다고 생각합니다. setState 호출을 하나만 수행하는 경우 일괄 처리 문제가 없습니다. 요점은 React가 배치를 업데이트한다는 것을 보여주는 것입니다. 그렇습니다. 실제로 위의 코드의 JSBin 버전에서 찾을 수있는 경우가 있습니다. 이 글타래의 거의 모든 답변이이 문제를 해결하지 못하기 때문에, 때때로 잘못된 코드가 많이있을 것입니다.
NealeU

state.array = state.array.concat([4])이것은 이전 상태 객체를 변경합니다.
Emile Bergeron

1
@EmileBergeron 감사합니다. 나는 결국 뒤돌아보고 내 뇌가 무엇을 보지 못하는지 보았고 문서를 확인 했으므로 편집 할 것이다.
NealeU

1
좋은! JS의 불변성이 명확하지 않기 때문에 잘못되기 쉽습니다 (심지어 라이브러리의 API를 처리 할 때 더 그렇습니다).
Emile Bergeron

17

주석에 언급 된 @ nilgun과 같이 반응 불변성 도우미를 사용할 수 있습니다 . 나는 이것이 매우 유용하다는 것을 알았다.

문서에서 :

간단한 푸시

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

initialArray는 여전히 [1, 2, 3]입니다.


6
React 불변성 헬퍼는 문서에서 더 이상 사용되지 않는 것으로 설명되어 있습니다. 대신 github.com/kolodny/immutability-helper를 사용해야합니다.
Periata Breatta

3

기능 컴포넌트를 사용하는 경우 다음과 같이 사용하십시오.

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

1

배열에 새로운 요소를 추가 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);

0

배열 상태에서 값을 푸시하고 이와 같은 값을 설정하고 맵 함수로 상태 배열을 정의하고 값을 푸시하려고합니다.

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

0

이것은 배열 내에 배열을 추가하는 데 효과적이었습니다.

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

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(', '))
        }

}

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

2
님이이 게시물을 저품질 게시물로 간주하지 않도록 설명을 추가하십시오 stackoverflow.
Harsha Biyani

2
@Kobe ES6에서 "spread operator"를 호출하고 array2 항목을 array1에 추가합니다. downvote에 감사드립니다 (:
M.Samiei

@ M.Samiei 당신은 downvotes를 피하기 위해 게시물을 편집해야합니다. 코드 스 니펫만큼 품질이 낮습니다. 또한 업데이트가 일괄 처리 될 수 setState(state => ({arrayvar: [...state.arrayvar, ...newelement]}) );
있으므로이

어쨌든 newelement배열 내에 객체를 퍼 뜨리면 던집니다 TypeError.
Emile Bergeron

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

-6

이 코드는 저에게 효과적입니다.

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

2
여전히, 당신은 직접 상태를 변경합니다
Asbar Ali

2
그리고 배열이 아닌 .push숫자를 반환 하므로 구성 요소의 상태를 올바르게 업데이트 하지 못합니다.
Emile Bergeron
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.