从Redux Form v6.0.0外部提交按钮

时间:2016-07-01 15:01:04

标签: javascript reactjs redux redux-form

这个问题与Redux Form v6.0.0有关(在写这个问题的时候是v6.0.0-alpha.15)。

如何从表单组件外部获取表单验证状态(如pristinesubmittinginvalid)?

让我举个例子。这是“经典的redux-form”伪结构:

<Form(MyExampleForm)>
    <MyExampleForm>
        <input name="title" ... />
        <submit-button />

... JSX中的<submit-button>如下所示:

<button type="submit" disabled={pristine || submitting || invalid} >Save</button>

但是在我的应用程序中,我的提交按钮必须位于表单之外,放在应用程序的不同位置(假设在应用程序标题中,在整个应用程序的顶部)。

  1. 如何从Redux-Form外部获取pristinesubmittinginvalid? (没有真正令人讨厌的黑客行为,如果可能的话: - )
  2. 我如何提交该表格?

7 个答案:

答案 0 :(得分:10)

只需装饰具有相同表单名称的另一个组件,您就可以访问相同的状态变量。你也可以从父传递它的onSubmit函数,并且能够从你定义它们的任何地方提交所有的Field值,因为它们都来自redux状态,而不是当前表单实例的HTML。 (这是一种“hacky”方式,但感觉还不错)

提交函数是从父级定义的,不是在状态中共享的,因此您可以为每个实例使其不同。

template <bool Signed, unsigned long long NofBits>
struct smallest_integer
{
    template<std::size_t Bits, class...Candidates>
    struct select_candidate;

    template<std::size_t Bits, class...Candidates>
    using select_candidate_t = typename select_candidate<Bits, Candidates...>::type;

    template<std::size_t Bits, class Candidate, class...Rest>
    struct select_candidate<Bits, Candidate, Rest...>
    {
        using type = std::conditional_t<std::numeric_limits<Candidate>::digits >= Bits, Candidate, select_candidate_t<Bits, Rest...>>;
    };

    template<std::size_t Bits, class Candidate>
    struct select_candidate<Bits, Candidate>
    {
        using type = std::conditional_t<std::numeric_limits<Candidate>::digits >= Bits, Candidate, void>;
    };

    using type =
    std::conditional_t<Signed,
    select_candidate_t<NofBits, std::int8_t, std::int16_t, std::int32_t, std::int64_t, __int128_t>,
    select_candidate_t<NofBits, std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t, __uint128_t>>;
};

template<bool Signed, unsigned long long NofBits> using smallest_integer_t = typename smallest_integer<Signed, NofBits>::type;

template<class L, class R>
struct result_of_multiply
{
    static constexpr auto lbits = std::numeric_limits<L>::digits;
    static constexpr auto rbits = std::numeric_limits<R>::digits;
    static constexpr auto is_signed = std::numeric_limits<L>::is_signed or std::numeric_limits<R>::is_signed;
    static constexpr auto result_bits = lbits + rbits;

    using type = smallest_integer_t<is_signed, result_bits>;
};

template<class L, class R> using result_of_multiply_t = typename result_of_multiply<L, R>::type;

struct safe_multiply
{
    template<class L, class R>
    auto operator()(L const& l, R const& r) const -> result_of_multiply_t<L, R>
    {
        return result_of_multiply_t<L, R>(l) * result_of_multiply_t<L, R>(r);
    }
};

template<class T>
auto accumulate_values(const std::vector<T>& v)
{
    using result_type = result_of_multiply_t<T, decltype(std::declval<std::vector<T>>().max_size())>;
    return std::accumulate(v.begin(), v.end(), result_type(0), std::plus<>());
}

struct uint128_t_printer
{

    std::ostream& operator()(std::ostream& os) const
    {
        auto n = n_;
        if (n == 0)  return os << '0';

        char str[40] = {0}; // log10(1 << 128) + '\0'
        char *s = str + sizeof(str) - 1; // start at the end
        while (n != 0) {

            *--s = "0123456789"[n % 10]; // save last digit
            n /= 10;                     // drop it
        }
        return os << s;
    }
    __uint128_t n_;
};
std::ostream& operator<<(std::ostream& os, const uint128_t_printer& p)
{
    return p(os);
}

auto output(__uint128_t n)
{
    return uint128_t_printer{n};
}

int main()
{
    using rtype = result_of_multiply<std::size_t, unsigned>;
    std::cout << rtype::is_signed << std::endl;
    std::cout << rtype::lbits << std::endl;
    std::cout << rtype::rbits << std::endl;
    std::cout << rtype::result_bits << std::endl;
    std::cout << std::numeric_limits<rtype::type>::digits << std::endl;

    std::vector<int> v { 1, 2, 3, 4, 5, 6 };
    auto z = accumulate_values(v);
    std::cout << output(z) << std::endl;


    auto i = safe_multiply()(std::numeric_limits<unsigned>::max(), std::numeric_limits<unsigned>::max());
    std::cout << i << std::endl;
}

答案 1 :(得分:4)

  

redux-form与React Redux一起使用,以使React中的html表单能够使用Redux来存储其所有状态。

如果&#34;在Redux-Form&#34;之外表示仍然是redux应用程序,您可以尝试通过调度某些操作来存储这些属性。

在表格中:您正在检测发生的事件(当其无效等)时,发出修改状态的动作, 在&#34;外面&#34; part:您将适当的属性传递给组件(与您需要的属性)并依赖于您禁用按钮。

答案 2 :(得分:3)

在最新的redux-form版本6.0.2中:

  1. 可以通过选择器http://redux-form.com/6.0.2/docs/api/Selectors.md/

  2. 访问表单状态invalidrecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { int action = e.getAction(); switch (action) { case MotionEvent.ACTION_MOVE: rv.getParent().requestDisallowInterceptTouchEvent(true); break; } return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } }); ucfirst = s => s[0].toUpperCase() + s.slice(1); rand = (min, max) => min + Math.floor(Math.random() * (max - min)); sample = a => a[rand(0, a.length)]; times = (n, fn) => [...Array(n)].map(fn); seq = (min, max, fn, sep) => times(rand(min, max), fn).join(sep); // this will use random "words" char = () => sample("abcdefghjiklmnopqrstuwvxyz"); word = seq(1, 10, char, ''); // this will use an array of predefined words words = [ 'the', 'be', 'to', 'of', 'and', 'a', 'in', 'that', 'have', 'I', 'it', 'for', 'not', 'on', 'with', 'he', 'as', 'you', 'do', 'at', 'this', 'but', 'his', 'by', 'from', 'they', 'we', 'say', 'her', 'she', 'or', 'an', 'will', 'my', 'one', 'all', 'would', 'there', 'their', 'what', 'so', 'up', 'out', 'if', 'about', 'who', 'get', 'which', 'go', 'me', 'when', 'make', 'can', 'like', 'time', 'no', 'just', 'him', 'know', 'take', 'person', 'into', 'year', 'your', 'good', 'some', 'could', 'them', 'see', 'other', 'than', 'then', 'now', 'look', 'only', 'come', 'its', 'over', 'think', 'also', 'back', 'after', 'use', 'two', 'how', 'our', 'work', 'first', 'well', 'way', 'even', 'new', 'want', 'because', 'any', 'these', 'give', 'day', 'most', 'us']; word = () => sample(words) phrase = () => seq(3, 10, word, ' '); sent = () => seq(1, 10, phrase, ', '); sentence = () => ucfirst(sent()) + sample('.?!'); paragraph = () => seq(1, 10, sentence, ' '); text = () => seq(2, 20, paragraph, '\n\n'); console.log(text())
  3. 可以导出redux-form动作创建者http://redux-form.com/6.0.2/docs/api/ActionCreators.md/

答案 3 :(得分:2)

也许您可以查看redux-forms的{​​{3}}。它提供对装饰表单组件实例的submit()方法的访问。还有pristine布尔属性和invalid布尔属性可用(还有Instance API来公开提交属性。)

此处有一个示例:request(示例适用于5.3.1,但该过程与使用Instance API的v6类似)

基本的想法是,通过在表单中​​添加ref="myExampleForm",您可以使用this.refs.myExampleForm传递它。然后,您可以检查实例的属性或调用submit()方法(或任何其他公开的方法)。

答案 4 :(得分:2)

现在更容易做到这一点。您可以在具有按钮的独立组件中调用“提交”操作。

查看此示例: https://redux-form.com/7.1.2/examples/remotesubmit/

答案 5 :(得分:1)

如果我们只是在提交表单,那么您应该向redux connect()函数提供{withRef:true} option

考虑具有子 RowDetail 组件的 Row 组件,该组件具有应从Row保存的信息。

在这种情况下,

RowDetail 可以像这样创建:

import { connect } from 'react-redux';
import { reduxForm } from 'redux-form';

const RowDetailForm = reduxForm({form: 'row-detail-form'})(RowDetail);

export default connect(mapStateToProps, null, null, {withRef: true})(RowDetailForm);

然后,在您的父组件( Row )中,使用ref属性创建表单:

<RowDetailForm ref={'rowDetailForm'} .../>  

现在提交简单&#39;:

onSave() {
  this.refs.rowDetailForm.getWrappedInstance().submit();
}

如果我们正在讨论pristine和其他表单属性,那么您可以尝试从组件中的mapStateToProps函数中获取它们。

const rowDetailFormName = 'row-detail-form';
const mapStateToProps = (state) => ({
  rowDetailForm: state.form[rowDetailFormName]
});

但是这种方式似乎有点hacky因为我理解redux-form API所有形式的状态从来都不是直接访问的。如果我错了,请纠正我

答案 6 :(得分:0)

我最近不得不解决这个问题。我最终将回调传递给表单,每当我感兴趣的属性发生变化时,都会调用该表单。 我使用componentDidUpdate生命周期方法来检测更改。

这适用于任何版本的库。

以下是包含示例代码的帖子 - http://nikgrozev.com/2018/06/08/redux-form-with-external-submit-button/