首页 > 解决方案 > 状态更新错误

问题描述

我有一个错误试图更新 React 中的状态。这是我的setState功能:

class App extends Component {
  state = {
      songs: [],
  }

  handleUpload = (songData) => {
    var songs = [...this.state.songs, songData];
    console.log(songs);
    this.setState({songs});
  }


  render() {
    return (
      <div>
        <div className="">
        <SidebarTopOverlay
          onUpload={this.handleUpload}
          logo={logo}/>

这是console.log的结果:

(1) […]
​
0: Object { title: "asdf", description: "", songFile: [], … }
​
length: 1
​
__proto__: Array []
App.js:19
(2) […]
​
0: Object { title: "asdfasdf", description: "", songFile: [], … }
​
1: Object { title: "asdfasdf", description: "", songFile: [], … }
​
length: 2
​
__proto__: Array []

如您所见,某些内容直接覆盖了状态,因为(编辑)在第二个日志上它不应该打印songFields要添加的重复项。

这是 UploadHandlers 类:

import React from 'react';
import UploadDropdown from '../../presentational-components/uploader/uploadDropdown.js';


const initialState = {
  songUploadFields: {
    title: '',
    description: '',
    songFile: [],
    genres: [],
  },
  uploadButtonToggle: true,
}

class UploadHandlers extends React.Component{
  state = initialState;

  reset = () => {
    this.setState(initialState);
  }


  handleInputChange = (e) => {
    const name = e.target.name;
    var value = e.target.value;
    var songUploadFields = this.state.songUploadFields;
    /*Title and SongFile are required to enable the upload button */
    if(name === 'title' && value.length > 0){
      this.setState({uploadButtonToggle: false});
    }else if(name === 'title'){
      this.setState({uploadButtonToggle: true});
    }
    /*don't allow two of the same genre,
    and allow user to subtract genres*/
    if(name === 'genres'){
      var genres = this.state.songUploadFields.genres;;
      if(!this.state.songUploadFields.genres.includes(value)){
        genres.push(value);
        value = genres;
      }else{
        var index = genres.indexOf(value)
        genres.splice(index, 1);
        value = genres;
      }
    //in case of songFile, change 'value' to handle file upload
    }else if(name==='songFile'){
      value = e.target.files[0];
    }
    //update the state
    songUploadFields[name] = value;
    this.setState({songUploadFields});
  }

  handleUpload = () => {
    this.props.onUpload(this.state.songUploadFields);
    this.reset();
  }


  render(){
    return(
      <UploadDropdown
        onUpload={this.handleUpload}
        onInputChange={this.handleInputChange}
        data={this.state}
      />
    )
  }
}

export default UploadHandlers

和 UploadDropdown (仅在模式中呈现它):

<Uploader
   onUpload={this.props.onUpload}
   onInputChange={this.props.onInputChange}
   data={this.props.data}
/>

和上传者:

import React from 'react';
import {Form, Button, Input, Dropdown} from 'semantic-ui-react';

/*Uploader is the form for uploading songs */
class Uploader extends React.Component{

  render(){
    const genres = [
      {
        key: 0,
        text: 'world',
        value: 'world',
      },
      {
        key: 1,
        text: 'folk',
        value: 'folk',
      },
      {
        key: 2,
        text: 'psychedelic',
        value: 'psychedelic',
      },
      {
        key: 3,
        text: 'funk',
        value: 'funk',
      },
    ];


    return(
      <div>
        <Form onSubmit={this.props.onUpload}>
          <Form.Field>
            <Input
              name='songFile'
              type="file"
              multiple
              onChange={this.props.onInputChange} />
          </Form.Field>
          <Form.Field>
            <label>Title</label>
            <Input
              type='text'
              name='title'
              placeholder='Title'
              value={this.props.data.songUploadFields.title}
              onChange={this.props.onInputChange}/>
          </Form.Field>
          <Form.Field>
            <label>Description</label>
            <Input
              type='text'
              name='description'
              placeholder='Description'
              value={this.props.data.songUploadFields.description}
              onChange={this.props.onInputChange}/>
          </Form.Field>
          <Form.Field>
            <label>Genres</label>
            <select
              name='genres'
              multiple
              value={this.props.data.songUploadFields.genres}
              onChange={this.props.onInputChange}>
              {genres.map((g, i) => <option key={i} value={g.value}>{g.text}</option>)}
            </select>
          </Form.Field>
          <Button type='submit' disabled={this.props.data.uploadButtonToggle}>Upload</Button>
        </Form>
      </div>
    )
  }
}

export default Uploader;

任何帮助,将不胜感激。

标签: reactjs

解决方案


问题是您的state操作不断修改与 共享的一组对象initialState,而不是创建新值,例如:

  var genres = this.state.songUploadFields.genres;
  if (!this.state.songUploadFields.genres.includes(value)) {
    genres.push(value);
    value = genres;
  }

genres是与 相同的对象引用initialState.songUploadFields.genres。当你推动它时,你也在改变initialState,破坏你的reset功能。

您总是需要创建一个副本,例如:

var genres = this.state.songUploadFields.genres.slice();

同样的问题也发生在songUploadFields对象上。它也与 中的对象完全相同initialState.songUploadFields。您需要在开始修改之前创建一个副本,例如:

var songUploadFields = Object.assign({}, this.state.songUploadFields); 

推荐阅读