这个问题与Redux Form v6.0.0有关(在写这个问题的时候是v6.0.0-alpha.15)。
如何从表单组件外部获取表单验证状态(如pristine
,submitting
,invalid
)?
让我举个例子。这是“经典的redux-form”伪结构:
<Form(MyExampleForm)>
<MyExampleForm>
<input name="title" ... />
<submit-button />
... JSX中的<submit-button>
如下所示:
<button type="submit" disabled={pristine || submitting || invalid} >Save</button>
但是在我的应用程序中,我的提交按钮必须位于表单之外,放在应用程序的不同位置(假设在应用程序标题中,在整个应用程序的顶部)。
pristine
,submitting
,invalid
? (没有真正令人讨厌的黑客行为,如果可能的话: - ))答案 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中:
invalid
,recyclerView.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())
可以导出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)
现在更容易做到这一点。您可以在具有按钮的独立组件中调用“提交”操作。
答案 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/