读取功能(无状态)组件中的<输入>

Read <input> in a functional (stateless) component

本文关键字:输入 组件 功能 状态 读取      更新时间:2023-09-26

我有两个组件:一个容器组件和一个表示组件。

容器使用表示组件获取显示帖子所需的所有信息和操作。在表示组件上,我有一种方法可以在呈现信息和编辑信息之间切换。当我编辑并提交有关帖子的数据时,我想从我拥有的所有不同输入中读取值,以便我可以调度操作。

但是,输入不在 <form id='theForm' onSubmit={onHandleSubmit}> 标记内。相反,<form>外部的所有<input><button type='submit'>都具有form='theForm'属性。

我以为我可以在表单之外有很多<input>,但只要 form 属性指向相应的<form>,我就可以使用 handleOnSubmit (e) {...} 接收的事件读取它的值。但是,我还没有弄清楚该怎么做。

如何读取handleOnSubmit函数上的输入值?或者这是一个我应该放弃的完全错误的想法?

// PostSummaryContainer.js
import React, { PropTypes, Component } from 'react'
import { connect } from 'react-redux'
import { loadPost, editPost, editPostCancel, editPostSubmit } from '../../actions/posts'
import PostSummaryView from '../../views/details/summary'
class PostSummaryContainer extends Component {
  constructor (props) {
    super(props)
    this.handleOnSubmit = this.handleOnSubmit.bind(this)
    this.handleOnCancel = this.handleOnCancel.bind(this)
    this.handleOnSubmit = this.handleOnSubmit.bind(this)
  }
  handleOnEdit (e) {
    e.preventDefault()
    this.props.editPost()
  }
  handleOnCancel (e) {
    e.preventDefault()
    this.props.editPostCancel()
  }
  handleOnSubmit (e) {
    e.preventDefault()
    // How do I read the input values? <--------------------
  }
  componentWillMount () {
    const {
      id,
      loadPost
    } = this.props
    loadPost(id)
  }
  render () {
    const {
      post,
      isLoading,
      isEditing
    } = this.props
    const viewProps = {
      bacon,
      isLoading,
      isEditing,
      handleOnEdit: this.handleOnEdit,
      handleOnCancel: this.handleOnCancel,
      handleOnSubmit: this.handleOnSubmit
    }
    return (
      <PostSummaryView {...viewProps} />
    )
  }
}
const mapStateToProps = (state, ownProps) => {
  const {
    params: {
      id
    }
  } = ownProps
  const post = state.entities.post[id]
  const {
    isLoading,
    isEditing
  } = state.posts
  return {
    id,
    post,
    isLoading,
    isEditing
  }
}
export default connect(
  mapStateToProps,
  { loadPost, editPost, editPostCancel, editPostSubmit }
)(PostSummaryContainer)

在我的演示文稿组件上:

// PostSummmaryView.js
import React from 'react'
import moment from 'moment'
function PostSummaryView (props) {
  const {
    post,
    isLoading,
    isEditing,
    handleOnEdit,
    handleOnCancel,
    handleOnSubmit
  } = props
  const formId = 'editPostForm'
  return (
    isLoading
      ? <div>Loading...</div>
      : <div className='row'>
          {isEditing && <form id={formId} onSubmit={handleOnSubmit}><input type='text' name='name' /></form>}
          <div className='col-md-6'>
            <img src={post.media.url} className='img-responsive' />
            {isEditing && <input type='file' name='media' form={formId}/>}
          </div>
          <div className='col-md-6'>
            <h1>{post.name}</h1>
            <p>
              {moment(post.publicationDate).format('dddd, MMMM Do')}
            </p>
            <hr />
            <p className='text-left'>
              {post.description || 'Lorem ipsum dolor sit amet, consectetur adipisici elit...'}
            </p>
            {isEditing
              ? <div>
                  <button className='btn btn-lg btn-default' onClick={handleOnCancel}>Cancel</button>
                  <button type='submit' className='btn btn-lg btn-default' form={formId}>Submit</button>
                </div>
              : <button className='btn btn-lg btn-default' onClick={handleOnEdit}>Edit</button>
            }
          </div>
        </div>
  )
}
export default PostSummaryView

免责声明:我仍然是 React/Redux 的新手,所以对这个答案持保留态度

我认为您的方法有偏差,因为您在提交时(无论是在<form>内部还是外部)都不需要四处走动并从输入中收集任何数据。您的州应始终位于一个中心、合并的位置。

如果您提供了"取消"选项,则在编辑期间在状态的单独部分中更新发布数据比直接修改"源"帖子数据更优雅(恕我直言)。

您可以为"编辑帖子"表单创建一个化简器,用于保留输入字段的键/值对。

当用户开始编辑时,您可以将原始 Post 数据克隆到特定于"编辑"窗体的状态的这个新部分。当用户更改输入时,您可以调度操作,说"嘿,表单字段 X 已更改为值 Y",可以在不修改原始 Post 数据的情况下将其缩减为状态。此流中状态对象的伪代码示例:

{
    // The actual Post data
    post: {
        media: {...},
        title: "My First Post",
        publicationDate: 1455768160589,
        description: "Lorem ipsum dolor sit amet"                  
    },
    // The temporary Post data in the Edit form
    postForm: {
        media: {...},
        title: "My Turbo-Charged First Post",
        publicationDate: 1455769951276,
        description: "Updated description yadda blah"                  
    }
}

然后,在演示文稿组件中,您可以将输入值从postForm而不是post 中驱动

每个输入都将被赋予一个更改处理程序函数,以便更新立即反映在状态中(或不反映,具体取决于您的验证逻辑/化简器)。即:

// In your actions associated with `Post`
// ------------------------------------------
function updateForm(field, value) {
    return {
        type: UPDATE_FORM,
        field,
        value
    }
}
// In your container
// ------------------------------------------
handleOnEdit(event) {
    postActions.updateForm(event.target.name, event.target.value)
}
// In your reducer
// ------------------------------------------
switch (action.type) {
    case UPDATE_FORM:
        return {
            ...state,
            [action.field]: action.value
        }
}
// In your presentational component's render() method
// ------------------------------------------
const {postForm, handleOnEdit} = this.props
const descriptionMarkup = (
    isEditing
    ? <input type='text' name='description' value={postForm.description} onChange={handleOnEdit} />
    : (post.description || 'Lorem ipsum dolor sit amet, consectetur adipisici elit...')
)
// ...
<p className='text-left'>
    {descriptionMarkup}
</p>

如果您遵循此模式(再次不确定它是否"正确"!),提交表单就像对您所在州的postForm对象执行某些操作一样简单。该对象应始终反映最新和最大的表单输入值。

取消窗体变得非常简单,只需将状态树的postForm部分设置为 {} 即可。原始帖子数据保持不变。

希望这有助于慢跑一些想法...

您可以尝试的其他一些示例/方法:

  • Erikras 的 redux-form
  • Nackjicholson的无状态形式示例
  • 冗余表单示例