使用 React 和 Javascript 保存动态创建的数据的最佳方法是什么?

IT技术 javascript reactjs
2021-05-07 10:49:44

我一直试图让我的动态表单工作,但我想知道最好的做法是保存这样生成的数据。

我的解决方案有效,但我觉得有更好的方法。

目前我将输入字段的两个值保存在一个单独的数组中。但实际上它们属于一起,所以我有一个链接值和一个我需要保存的内容值。

稍后我需要映射这些值以使用存储的值创建新元素。

我现在的问题是我不知道如何同时映射两个数组。我还想知道是否最好只创建一个具有所有这些值的对象,然后再映射它。

希望有人可以帮助我。

这是我的代码:

class MediaInput extends React.Component {
  render() {
    const linkName = `link${this.props.index}`;
    const contentName = `content${this.props.index}`;

    return (
      <div>
      <ControlLabel>Media (optional)</ControlLabel>
        <input
        onChange={(event) => this.props.handleChangeUrl(event, this.props.index)}
        name={ linkName }
        value={ this.props.mediaUrls[this.props.index]}
        className="form-control"
        placeholder="Add your media url. We accept YouTube, Vimeo and SoundCloud links" 
        type="text" 
        />
        <input
        name={ contentName }
        onChange={(event) => this.props.handleChangeContent(event, this.props.index)}
        value={ this.props.mediaContents[this.props.index]}
        className="form-control" 
        placeholder="Add your media content"
        type="text" 
        />
    </div>
    );
  }
}

export default class AddSparkShanghai extends Component {
  constructor(props) {
    super(props);

    this.createSpark = this.createSpark.bind(this);
    this.onChange = this.onChange.bind(this);
    this.handleChangeUrl = this.handleChangeUrl.bind(this);
    this.handleChangeContent = this.handleChangeContent.bind(this);


    this.state ={
      mediaFields: [],
      content: [],
      mediaUrls: [ null, null, null ],
      mediaContents: [ {'', '', ''],
    };
  }

[...]

// Add/remove media fields 

  add() {
    event.preventDefault();
    const mediaFields = this.state.mediaFields.concat(MediaInput);
    if (i < 3) {
      this.setState({ mediaFields });
      i++
    } else {
      Bert.alert('Only 3 media links are allowed', 'danger');
    }
  }

  remove() {
    event.preventDefault();
    const lastElement = this.state.mediaFields.pop();
    const mediaFields = this.state.mediaFields;
    this.setState({ mediaFields });
    i--
  }

// Handle change media fields 

  handleChangeUrl(e, index) {
    // Shallow copy of array
    const mediaUrls = this.state.mediaUrls.slice();
    let url = e.target.value
    if (!/^https?:\/\//i.test(url)) {
      url = 'http://' + url;
    }

    mediaUrls[index] = url;
      this.setState({ mediaUrls});
  }

  handleChangeContent(e, index) {
    // Shallow copy of array
    const mediaContents = this.state.mediaContents.slice();
    mediaContents[index] = e.target.value;
      this.setState({ mediaContents });
  }

[...]

 const mediaFields = this.state.mediaFields.map((Element, index) => {
      return <Element key={ index } index={ index } mediaUrls={this.state.mediaUrls} mediaContents={this.state.mediaContents} handleChangeUrl={this.handleChangeUrl} handleChangeContent={this.handleChangeContent} />
  }) 

[...]

<div>
    { mediaFields }
    <Button onClick={ () => this.add() }>Add media field</Button>
    <Button onClick={ () => this.remove() }>Remove media field</Button>
</div>

2个回答

未经测试的代码,但如果您更改以下内容,它应该可以工作:

改变这个:

this.state ={
  mediaFields: [],
  content: [],
  mediaUrls: [ null, null, null ],
  mediaContents: [ {'', '', ''],
};

到:

this.state ={
  mediaFields: [],
  content: [],
  data: [],
};

并改变:

handleChangeUrl(e, index) {
  // Shallow copy of array
  const mediaUrls = this.state.mediaUrls.slice();
  let url = e.target.value
  if (!/^https?:\/\//i.test(url)) {
    url = 'http://' + url;
  }

   mediaUrls[index] = url;
   this.setState({ mediaUrls});
}

到:

handleChangeUrl(e, index) {
  // Shallow copy of array
  const tempData = this.state.data.slice();
  let url = e.target.value
  if (!/^https?:\/\//i.test(url)) {
    url = 'http://' + url;
  }

  tempData[index].link = url;
  this.setState({ tempData });
}

并改变:

handleChangeContent(e, index) {
  // Shallow copy of array
  const mediaContents = this.state.mediaContents.slice();
  mediaContents[index] = e.target.value;
  this.setState({ mediaContents });
}

到:

handleChangeContent(e, index) {
  // Shallow copy of array
  const tempData = this.state.data.slice();
  tempData[index].content = e.target.value;
  this.setState({ tempData });
}

最后:

add() {
  event.preventDefault();
  const mediaFields = this.state.mediaFields.concat(MediaInput);
  if (i < 3) {
    this.setState({ mediaFields });
    i++
  } else {
    Bert.alert('Only 3 media links are allowed', 'danger');
  }
}

remove() {
  event.preventDefault();
  const lastElement = this.state.mediaFields.pop();
  const mediaFields = this.state.mediaFields;
  this.setState({ mediaFields });
  i--;
}

到:

add() {
  event.preventDefault();
  const mediaFields = this.state.mediaFields.concat(MediaInput);
  const data = this.state.data.slice();
  data.push({ link: "", content: "" });
  if (i < 3) {
    this.setState({ data, mediaFields });
    i++
  } else {
    Bert.alert('Only 3 media links are allowed', 'danger');
  }
}

remove() {
  event.preventDefault();
  const lastElement = this.state.mediaFields.pop();
  const mediaFields = this.state.mediaFields;
  const data = this.state.data.slice();
  data.pop();
  this.setState({ data, mediaFields });
  i--;
}

注意:已编辑以修复最后的大量更改!

JosephGarrone的帮助下,我能够让这个例子像我想要的那样工作!

这是完整的代码:

class MediaInput extends React.Component {
  render() {
    const linkName = `link${this.props.index}`;
    const contentName = `content${this.props.index}`;

    return (
      <div>
      <ControlLabel>Media (optional)</ControlLabel>
        <input
        onChange={(event) => this.props.handleChangeUrl(event, this.props.index)}
        name={ linkName }
        value={ this.props.mediaData[this.props.index].link}
        className="form-control"
        placeholder="Add your media url. We accept YouTube, Vimeo and SoundCloud links" 
        type="text" 
        />
        <input
        name={ contentName }
        onChange={(event) => this.props.handleChangeContent(event, this.props.index)}
        value={ this.props.mediaData[this.props.index].content}
        className="form-control" 
        placeholder="Add your media content"
        type="text" 
        />
    </div>
    );
  }
}

export default class AddSparkShanghai extends Component {
  constructor(props) {
    super(props);

    this.handleChangeUrl = this.handleChangeUrl.bind(this);
    this.handleChangeContent = this.handleChangeContent.bind(this);


    this.state ={
      mediaFields: [],
      mediaData: [],
    };
  }

[...]

  // Add/remove media fields 

add() {
  event.preventDefault();
  const mediaFields = this.state.mediaFields.concat(MediaInput);
  const mediaData = this.state.mediaData.slice();
  mediaData.push({ link: "", content: "" });
  if (i < 3) {
    this.setState({ mediaData, mediaFields });
    i++
  } else {
    Bert.alert('Only 3 media links are allowed', 'danger');
  }
}

remove() {
  event.preventDefault();
  const lastElement = this.state.mediaFields.pop();
  const mediaFields = this.state.mediaFields;
  const mediaData = this.state.mediaData.slice();
  mediaData.pop();
  this.setState({ mediaData, mediaFields });
  i--;
}

// Handle change media fields 

handleChangeUrl(e, index) {
  // Shallow copy of array
  const tempData = this.state.mediaData.slice();
  let url = e.target.value
  if (!/^https?:\/\//i.test(url)) {
    url = 'http://' + url;
  }

  tempData[index].link = url;
  this.setState({ mediaData: tempData });
  console.log(this.state.mediaData)
}

handleChangeContent(e, index) {
  // Shallow copy of array
  const tempData = this.state.mediaData.slice();
  tempData[index].content = e.target.value;
  this.setState({ mediaData: tempData });
  console.log(this.state.mediaData)
}

[...]

  const mediaFields = this.state.mediaFields.map((Element, index) => {
      return <Element key={ index } index={ index } mediaData={this.state.mediaData}  handleChangeUrl={this.handleChangeUrl} handleChangeContent={this.handleChangeContent} />
  })    

[...]

<div>
    { mediaFields }
    <Button onClick={ () => this.add() }>Add media field</Button>
    <Button onClick={ () => this.remove() }>Remove media field</Button>
</div>