使用具有多个提交的子组件的子组件来响应 Redux-Form [英] React Redux-Form using child components with child components that have multiple submits

查看:46
本文介绍了使用具有多个提交的子组件的子组件来响应 Redux-Form的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

React-Redux 的新手.

我有一个使用handleSubmit"的子组件,这部分代码有效.

 props.onSubmit({...值,sortBy: '客户编号'}))}><span>客户端编号 </span></span>

这是上面代码的子组件,包含所有相关部分.

export const TableHeaders = (props) =>{const { handleSubmit } = 道具const { sortBy, sortDirection } = props返回 (<div><div className="row"><div className="col-md-2" style={headingCellStyle}><跨度样式={textLinkStyle}onClick={handleSubmit(values =>props.onSubmit({...值,sortBy: '客户编号'}))}><span>客户端编号 </span></span><GlyphiconDirectionChange sortDirection={sortDirection}/>......)}TableHeaders.propTypes = {onSubmit: PropTypes.func.isRequired,}const TableHeadersForm = reduxForm({形式:'表头',})(表头)导出默认 TableHeadersForm

所以我想将这个组件的重复部分分成单独的较小组件,以便我可以重用它们.所以上面的组件现在是下面的组件.

然而,它也有多个提交,一个用于向上排序,另一个用于向下排序......我认为它会一直传播到顶级父级,但唉......没有.

这是我试过的.

const GlyphiconDirectionChange = (props) =>{const { handleSubmit } = 道具const { sortDirection } = 道具返回 (<跨度>{sortDirection === '降序' ?<跨度样式={textLinkStyle}onClick={handleSubmit(values =>props.onSubmit({...值,sortDirection: '升序'}))}className='glyphicon glyphicon-sort-by-attributes'></span>:<跨度样式={textLinkStyle}onClick={handleSubmit(values =>props.onSubmit({...值,sortDirection: '降序'}))}className='glyphicon glyphicon-sort-by-attributes-alt'></span>}</span>)}

我发现 handleSubmit 在 TableHeader 组件中用作较大父组件的一部分时起作用 - 它的下一级.一阶孩子.

它在 GlyphiconDirectionChange 组件中不起作用.二阶孩子...为什么?

我在控制台中收到以下错误

<块引用>

异常:调用节点模块失败,错误:TypeError:handleSubmit 不是函数

这是一个语法错误.我应该如何处理handleSubmit",同时当它的子组件也是子组件的一部分时发送更新的值.

总结一下.HandleSubmit 在子组件中工作,但在子组件的子组件中不起作用......第二级......

编辑

我注意到#Dennis 建议我使用 despatch 而不是使用 handleSubmit.这是完整的 ClientsContainer:

import React, { Component, PropTypes } from 'react'从'react-redux'导入{连接}从./Clients"导入客户从./SearchClients"导入 SearchClients从 './TableHeaders' 导入 TableHeaders从 './reducer' 导入 { requestClients }类 ClientsContainer 扩展组件 {静态上下文类型 = {路由器:PropTypes.object.isRequired}componentDidMount() {如果(!this.props.isAuthorised){this.context.router.push('/')返回}this.fetchClients()}fetchClients = (values = {}) =>{const { currentPage, query, sortBy, sortDirection } = this.propsconst searchParams = {当前页面,询问,排序方式,排序方向,...值,}console.log('fetchClients()!', values, searchParams)this.props.requestClients(searchParams)}客户搜索 = (值 = {}) =>{const { query, sortBy, sortDirection } = this.propsvalues.query = values.query ||''const searchParams = {询问,排序方式,排序方向,...值,当前页面:1,}console.log('clientsSearch()!', values, searchParams)this.fetchClients(searchParams)}changeHeaders = (values = {}) =>{const { query, sortBy, sortDirection } = this.propsvalues.query = values.query ||''const searchParams = {询问,排序方式,排序方向,...值,当前页面:1,}console.log('changeHeaders()!', values, searchParams)this.fetchClients(searchParams)}handlePageChanged = (pageIndex) =>{this.fetchClients({当前页面:页面索引,})}使成为() {const { 客户端、currentPage、查询、sortBy、sortDirection、totalClients、totalPages } = this.props返回 (<div className="row"><div className="col-md-12"><SearchClients onSubmit={this.clientsSearch}当前页={当前页}查询={查询}sortBy={sortBy}sortDirection={sortDirection}/><TableHeaders onSubmit={this.changeHeaders}当前页={当前页}查询={查询}sortBy={sortBy}sortDirection={sortDirection}/><客户客户={客户}当前页={当前页}查询={查询}sortBy={sortBy}sortDirection={sortDirection}totalClients={totalClients}总页数={总页数}onPageChanged={this.handlePageChanged}/>

)}}const mapStateToProps = (状态) =>({isAuthorised: state.login.isAuthorised,客户:state.clients.clients,当前页面:state.clients.currentPage,查询:state.clients.query,sortBy: state.clients.sortBy,sortDirection: state.clients.sortDirection,totalClients: state.clients.totalClients,totalPages:state.clients.totalPages,})const mapDispatchToProps = (调度) =>({requestClients:(值)=>调度(请求客户端(值)),})导出默认连接(mapStateToProps,mapDispatchToProps)(ClientsContainer)

它确实有发送到减速器的地方.再次.. 如果我想将表单组件化为多个组件,其中一个可能是作为链接的标题.. 当它可能是当前父组件的组件的组件时,最好的方法是什么是唯一一个发送...

解决方案

是否绝对有必要提交诸如排序方向之类的内容,或者这在某种程度上与您的后端相关?在我看来,这应该是对客户的责任.

把它留给客户端还有一个额外的好处,那就是让这一切变得更简单,因为当你想要改变排序方向时,你可以只调度一个常规动作.然后,该操作可以使用请求的排序方向调用您的后端,并相应地更新新状态.

根据您处理的数据量,您甚至可以选择根本不调用后端,而将排序完全交给客户端.

关于您的 TableHeaders 组件,我会这样做:

让组件通过 props 接受一个事件处理函数,这样你就可以在组件内部的排序发生变化时通知容器.

这适用于更小的组件,因为您只是通过 props 传递函数.

简化示例:

export const TableHeaders = (props) =>{const { onSortByChange, onSortDirectionChange } = props;返回 (<div><span onClick={() =>onSortByChange('ClientNumber')}>客户端#</span><span onClick={() =>onSortByChange('SomethingElse')}>别的东西</span><GlyphiconDirectionChange onSortDirectionChange={onSortDirectionChange}/>

);}const GlyphiconDirectionChange = (props) =>{const { onSortDirectionChange } = props;返回 (<div><span onClick={() =>onSortDirectionChange('asc')}>Asc</span><span onClick={() =>onSortDirectionChange('desc')}>Desc</span>

);}

然后在你的容器中你可以这样做:

class ClientsContainer 扩展组件 {handleSortDirection =(方向)=>{//调用 Redux 操作来更新您的排序方向状态}handleSortBy = (by) =>{//调用 Redux 操作以按状态更新您的排序}使成为() {返回 (<div><表头onSortByChange={this.handleSortBy}onSortDirectionChange={this.handleSortDirection}/* 其他道具 *//>

);}}

为了获取新数据,您可以实现 componentWillUpdate 并检查排序方式或排序方向是否已更改,如果已更改,则根据更新的 props 获取新数据.

但是,我觉得将它和从组件中获取数据的部分移动到异步操作创建器中会更优雅.这样你的组件的责任就更少了.

New to React-Redux.

I have a child component that uses the following with "handleSubmit" and this part of the code works.

        <span
        style={textLinkStyle}
        onClick={handleSubmit(values =>
          props.onSubmit({
            ...values,
            sortBy: 'ClientNumber'
          }
          ))}>
        <span>Client # </span>
      </span>

Here is the above code's child component with all the relevant parts.

export const TableHeaders = (props) => {
  const { handleSubmit } = props

  const { sortBy, sortDirection } = props

  return (
    <div>
      <div className="row">
        <div className="col-md-2" style={headingCellStyle}>
          <span
            style={textLinkStyle}
            onClick={handleSubmit(values =>
              props.onSubmit({
                ...values,
                sortBy: 'ClientNumber'
              }
              ))}>
            <span>Client # </span>
          </span>

          <GlyphiconDirectionChange sortDirection={sortDirection}/>
          ......

  )
}
TableHeaders.propTypes = {
  onSubmit: PropTypes.func.isRequired,
}

const TableHeadersForm = reduxForm({
  form: 'TableHeaders',
})(TableHeaders)

export default TableHeadersForm

So I wanted to separate repetative parts of this component into separate smaller components so I could reuse them. So the above component is now the parent of the following.

However it also has multiple submits one for sort direction up and one for sort direction down... I thought it would propagate all the way up to the top parent but alac alas.. no.

This is what I tried.

const GlyphiconDirectionChange = (props) => {
  const { handleSubmit } = props
  const { sortDirection } = props

  return (
    <span>
      {sortDirection === 'Descending' ?
        <span
          style={textLinkStyle}
          onClick={handleSubmit(values =>
            props.onSubmit({
              ...values,
              sortDirection: 'Ascending'
            }
            ))}
          className='glyphicon glyphicon-sort-by-attributes'>
        </span>
        :
        <span
          style={textLinkStyle}
          onClick={handleSubmit(values =>
            props.onSubmit({
              ...values,
              sortDirection: 'Descending'
            }
            ))}
          className='glyphicon glyphicon-sort-by-attributes-alt'>
        </span>
      }
    </span>
  )}

What I found is that handleSubmit works when it is used in the the TableHeader component as part of a larger parent component -its one level down. A first order child.

It does not work in the GlyphiconDirectionChange component. the second order child... Why?

I get the following error in the console

Exception: Call to Node module failed with error: TypeError: handleSubmit is not a function

This is a syntax error. How should I deal with the "handleSubmit" while also sending the updated values when its part of child that is also a child component.

So to recap. HandleSubmit works in the child but doesnt work in the the child component's child.. second level down...

EDIT

I note that #Dennis has suggested I use a despatch instead of using handleSubmit. This is the full ClientsContainer:

import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import Clients from './Clients'
import SearchClients from './SearchClients'
import TableHeaders from './TableHeaders'
import { requestClients } from './reducer'

class ClientsContainer extends Component {
  static contextTypes = {
    router: PropTypes.object.isRequired
  }

  componentDidMount() {
    if (!this.props.isAuthorised) {
      this.context.router.push('/')
      return
    }

    this.fetchClients()
  }

  fetchClients = (values = {}) => {
    const { currentPage, query, sortBy, sortDirection } = this.props
    const searchParams = {
      currentPage,
      query,
      sortBy,
      sortDirection,
      ...values,
    }
    console.log('fetchClients()!', values, searchParams)
    this.props.requestClients(searchParams)
  }

  clientsSearch = (values = {}) => {
    const { query, sortBy, sortDirection } = this.props
    values.query = values.query || ''
    const searchParams = {
      query,
      sortBy,
      sortDirection,
      ...values,
      currentPage: 1,
    }
    console.log('clientsSearch()!', values, searchParams)
    this.fetchClients(searchParams)
  }

  changeHeaders = (values = {}) => {
    const { query, sortBy, sortDirection } = this.props
    values.query = values.query || ''
    const searchParams = {
      query,
      sortBy,
      sortDirection,
      ...values,
      currentPage: 1,
    }
    console.log('changeHeaders()!', values, searchParams)
    this.fetchClients(searchParams)
  }

  handlePageChanged = (pageIndex) => {
    this.fetchClients({
      currentPage: pageIndex,
    })
  }

  render() {
    const { clients, currentPage, query, sortBy, sortDirection, totalClients, totalPages } = this.props

    return (
      <div className="row">
        <div className="col-md-12">
          <SearchClients onSubmit={this.clientsSearch}
            currentPage={currentPage}
            query={query}
            sortBy={sortBy}
            sortDirection={sortDirection}
          />
          <TableHeaders onSubmit={this.changeHeaders}
            currentPage={currentPage}
            query={query}
            sortBy={sortBy}
            sortDirection={sortDirection}
          />
          <Clients clients={clients}
            currentPage={currentPage}
            query={query}
            sortBy={sortBy}
            sortDirection={sortDirection}
            totalClients={totalClients}
            totalPages={totalPages}
            onPageChanged={this.handlePageChanged}
          />
        </div>
      </div>
    )
  }
}

const mapStateToProps = (state) => ({
  isAuthorised: state.login.isAuthorised,
  clients: state.clients.clients,
  currentPage: state.clients.currentPage,
  query: state.clients.query,
  sortBy: state.clients.sortBy,
  sortDirection: state.clients.sortDirection,
  totalClients: state.clients.totalClients,
  totalPages: state.clients.totalPages,
})
const mapDispatchToProps = (dispatch) => ({
  requestClients: (values) => dispatch(requestClients(values)),
})
export default connect(mapStateToProps, mapDispatchToProps)(ClientsContainer)

It does have despatch which is where it goes to the reducer. Again.. if I want to componentize a form into many components one of which might be a header that is a link.. whats the best way to do this when it might be a component of a component of a parent component that at the moment is the only one that despatches...

解决方案

Is it absolutely necessary to submit stuff like sort directions, or is that in some way relevant to your backend? Seems to me like this should be a responsibility for the client.

Leaving it up to the client also has an added benefit of making all this a lot simpler, since you could just dispatch a regular action for when you want to change sort direction. That action could then call your backend with the requested sort direction and that can update the new state accordingly.

Depending on the amount of data you're dealing with, you could even choose to not call your backend at all and leave the sorting entirely up to the client.

Regarding your TableHeaders component, here's what I would do:

Have the component accept an event handler function via props, so you can notify the container when the sorting changes inside the component.

This works just fine for more smaller components, since you're just passing around functions via props.

Simplified example:

export const TableHeaders = (props) => {
  const { onSortByChange, onSortDirectionChange } = props;

  return (
    <div>
      <span onClick={() => onSortByChange('ClientNumber')}>Client #</span>
      <span onClick={() => onSortByChange('SomethingElse')}>Something else</span>

      <GlyphiconDirectionChange onSortDirectionChange={onSortDirectionChange} />
    </div>
  );
}

const GlyphiconDirectionChange = (props) => {
  const { onSortDirectionChange } = props;

  return (
    <div>
      <span onClick={() => onSortDirectionChange('asc')}>Asc</span>
      <span onClick={() => onSortDirectionChange('desc')}>Desc</span>
    </div>
  );
}

Then in your container you can do this:

class ClientsContainer extends Component {
  handleSortDirection = (direction) => {
    // Call Redux action to update your sort direction state
  }

  handleSortBy = (by) => {
    // Call Redux action to update your sort by state
  }

  render() {
    return (
      <div>
        <TableHeaders
          onSortByChange={this.handleSortBy}
          onSortDirectionChange={this.handleSortDirection}
          /* other props */
        />
      </div>
    );
  }
}

In order to get the new data, you could implement componentWillUpdate and check if sort by or sort direction have changed and if so, fetch new data based on updated props.

However, I feel it would be more elegant to move that and the data fetching part from your component into an async action creator. That way your component has less responsibilities.

这篇关于使用具有多个提交的子组件的子组件来响应 Redux-Form的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆