简体   繁体   中英

.push() does not work in the constructor?

I have an array as such:

product = [
    {
        name: " size one",
        price: 1
      },
      {
        name: "size two",
        price: 2
      },
      ,
      {
        name: "size three",
        price: 3
      }
    ];

I had previously separated odd and even array indexes like this:

for (let i=0; i< product.length; i++ ) {
      if (i % 2 === 0 ){
        evenArray.push(product[i])
      } else {
        oddArray.push(product[i])
      }
    };

But I would like to move this to the constructor and out of render. I have it written like this in a componenetDidMount() :

  for (let i=0; i< this.state.product.length; i++ ) {
      if (i % 2 === 0 ){
        this.setState({
        evenArray: [...this.state.evenArray, this.state.product[i]]
      });
      } else {
        this.setState({
        oddArray: [...this.state.oddArray, this.state.product[i]]
      });
      }
    };

But it doesn't work. I'm familiar with the idea that you cannot change the state directly but update it only which is why .push() can't be used but how come the above does not work?

-----EDIT OF REAL CODE-----

componentDidMount() {
  const oauth = OAuth({
    consumer: {
      key: 'XXXXXXXXX',
      secret: 'XXXXXXXXXXX',
    },
    signature_method: 'HMAC-SHA1',
    hash_function(base_string, key) {
      return crypto.createHmac('sha1', key).update(base_string).digest('base64');
    }
  });

  const request_data1 = {
    url: 'http://localhost:8888/wp-json/wc/v2/products/28/variations?per_page=15',
    method: 'GET',
  };

  const request_data2 = {
    url: 'http://localhost:8888/wp-json/wc/v2/products/28/',
    method: 'GET',
  };

  fetch(request_data1.url, {
    method: request_data1.method,
    headers: oauth.toHeader(oauth.authorize(request_data1))
  })
    .then(response => response.json())
    .then(response => {
      this.setState({
         products1: response.reverse()
      })
   })

   fetch(request_data2.url, {
     method: request_data2.method,
     headers: oauth.toHeader(oauth.authorize(request_data2))
   })
     .then(response => response.json())
     .then(response => {
       this.setState({
          products2: response
       })
    })

    const evenArray = [];
    const oddArray = [];
    for (let i = 0; i < this.state.products1.length; i++) {
      if (i % 2 === 0) {
        evenArray.push( this.state.products1[i] );
      } else {
        oddArray.push(this.state.products1[i]);
      }
    };

    this.setState( prevState => ({
        evenArray: [ ...prevState.evenArray, ...evenArray ],
        oddArray: [...prevState.oddArray, ...oddArray],
    }));

}

You can't set your state successfully since your for loop finishes before you set the state. I don't like for loops for this reason and we generally don't use them but you can do it in this way:

 class App extends React.Component { state = { product: [ { name: " size one", price: 1 }, { name: "size two", price: 2 }, { name: "size three", price: 3, } ], evenArray: [], oddArray: [], } componentDidMount() { const evenArray = []; const oddArray = []; for (let i = 0; i < this.state.product.length; i++) { if (i % 2 === 0) { evenArray.push( this.state.product[i] ); } else { oddArray.push(this.state.product[i]); } }; this.setState( prevState => ({ evenArray: [ ...prevState.evenArray, ...evenArray ], oddArray: [...prevState.oddArray, ...oddArray], })); } render() { console.log( this.state ); return <div> Evens: {JSON.stringify(this.state.evenArray)} Odds: {JSON.stringify(this.state.oddArray)} </div>; } } ReactDOM.render(<App />, document.getElementById("root")); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="root"></div> 

Update after comments

Since you are fetching your data, before it finishes again you are trying to set your state. I tried to mimic the situation. This is just one way of many solutions.

 const product1 = [ { name: " size one", price: 1 }, { name: "size two", price: 2 }, { name: "size three", price: 3, } ]; const fakeRequest = () => new Promise( resolve => setTimeout( () => resolve( product1 ), 2000 ) ); class App extends React.Component { state = { product1: [], evenArray: [], oddArray: [], } componentDidMount() { fakeRequest() .then( product1 => { const evenArray = product1.filter((el, i) => i % 2 === 0); const oddArray = product1.filter((el, i) => i % 2 !== 0); this.setState( prevState => ( { product1: [ ...prevState.product1, ...product1 ], evenArray: [...prevState.evenArray, ...evenArray ], oddArray: [...prevState.oddArray, ...oddArray], } )) }) } render() { console.log(this.state); return <div> { !this.state.product1.length && <p>Waiting for 2 seconds...</p> } Evens: {JSON.stringify(this.state.evenArray)} Odds: {JSON.stringify(this.state.oddArray)} </div>; } } ReactDOM.render(<App />, document.getElementById("root")); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="root"></div> 

Second update

I used the fakeRequest to mimic your situation, don't use it. Your code will probably something like this:

fetch(request_data1.url, {
    method: request_data1.method,
    headers: oauth.toHeader(oauth.authorize(request_data1))
  })
    .then(response => response.json())
    .then(response => {
         const products1 = response.reverse();
         const evenArray = products1.filter((el, i) => i % 2 === 0);
         const oddArray = products1.filter((el, i) => i % 2 !== 0);
         this.setState( prevState => ( {
              product1: [ ...prevState.products1, ...product1 ],
              evenArray: [...prevState.evenArray, ...evenArray ],
              oddArray: [...prevState.oddArray, ...oddArray],
         } ))
})

You shouldn't call this.setState in the constructor. Instead just set it as the initial state:

constructor(props) {
  super(props);
  this.state = {
    evenArray: evenArray, 
    oddArray: oddArray,
  };
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM