簡體   English   中英

如何處理每個字段的異步更新onUpdate並使用redux-form和redux-observable保持ID

[英]How to handle async update onUpdate of each field and keep ids using redux-form and redux-observable

我在我的應用程序中使用redux-observable,並嘗試為我的情況添加redux-form(異步驗證,跟蹤所有操作),在這種情況下,我需要制作一個在每次數據更改時都進行異步調用的表單。 我不想手動提交表單並提出集中提交請求(如官方示例所做的那樣)。

考慮到redux-form在每個字段@@redux-form/CHANGE上都派發一個@@redux-form/CHANGE動作,因此很容易利用redux-observable並“監聽”該動作並基於其進行一些限制,取消,重試等在這些動作上。 每個異步調用(一旦將其保存到db中)將返回特定字段的ID。

根據以下代碼示例,取自redux-form-redux-observable

const registerEpic = (action$, { getState, dispatch }) =>
  action$.ofType('REQUEST_SUBMIT')
    .do(dispatch(startSubmit('contact')))
    .mergeMap(action => 
      fromPromise(submitToServer(action.data))  
      .map(response => {
        console.log(response);
        dispatch(stopSubmit('contact', response.errors || {}));
        if (response.errors) {
          return {
            type: 'REQUEST_FAILED',
            errors: response.errors,
          }
        } else {
          return {
            type: 'REQUEST_SUCCESSFUL'
          }
        }
      })
    );

我嘗試處理從redux-form分派的操作。 調度@@redux-form/CHANGE ,它將進行服務器調用,當此調用解析后,我將從服務器獲取字段ID。 我可能需要將其添加到表單的存儲中,並在需要對服務器進行此特定字段的DELETE請求后,將其用作“將來使用”的參考。

我認為解決此問題的方法是從服務器解析完數據后調度redux-form change操作,但這再次觸發@@redux-form/CHANGE ,並且表單(顯然)在我進入無限循環之后繼續收聽@@redux-form/CHANGE操作。

const updateEpic = (action$, { getState, dispatch }) =>
  action$.ofType('@@redux-form/CHANGE')
    .debounceTime(1000)
    .do(x => console.log(x))
    .do(x => console.log(getState().form.contact.values[x.meta.field]))
    .mergeMap(action => 
      fromPromise(submitToServer(xxx))  
      .map(response => {
        dispatch(change('contact', 'firstName', 'test'));
      })
    );

因此,我在這里遇到了一些困難的案例:

  • 我如何將服務器返回的ID添加到商店(以備將來使用)

  • 如何通過引入另一種方式來處理我的案件來巧妙地避免這種無限期

  • 最后,我想知道redux-observable和redux-form的組合是否適合我的需求。

謝謝

更新

我最終設法通過使用reducer.plugin()調度了一個新操作,並將從服務器返回的數據應用於每個字段的meta數據,從而解決了此問題。

下面是一個簡單的例子

const updateEpic = (action$, { getState, dispatch }) =>
    action$.ofType('@@redux-form/CHANGE')
        .debounceTime(1000)
        .do(x => console.log(x))
        .do(x => console.log(getState().form.contact.values[x.meta.field]))
        .mergeMap(action =>
            fromPromise(submitToServer(xxx))
                .map(response => {
                    return {
                        action: 'CUSTOM_ACTION',
                        payload: {
                            id: response.id,
                            meta: action.meta // <-- this is the initial action that helps you to know which is the field you need to update
                        }
                    }
                })
        );

對於減速器側

myReducer(state = {}, action) {
    switch (action.type) {
        case 'CUSTOM_ACTION':
            return  merge({}, state, {
                [action.payload.meta.form]: {
                    fields: {
                        [action.payload.meta.field]: {
                            id: action.payload.id
                        }
                    }
                }
            })
            break;
        default:
            return state
    }
}

最后,您可以從React Component中的meta獲取id

const renderField = ({ type, label, input, meta: { touched, error, warning, id = undefined } }) => (
    <div className="input-row">
        <pre>{id}</pre>
        <label>{label}</label>
        <input {...input} type={type}/>
        {touched && error &&
        <span className="error">{error}</span>}
        {touched && warning &&
        <span className="warning">{warning}</span>}
    </div>
);

如果其他人有更好的解決方案,我想告訴我們。 我認為這個問題是封閉的。

@stelioschar,我對其進行了研究,發現您可以采用這種方法,我認為它非常有效,我將代碼留在這里,如果其他人對此有所不同,請分享。

當用戶鍵入時,我正在驗證,當它達到6個字母時,我向服務器發送了一個請求:

export const validateUserNameEpic = function (action$, store) {
    return action$.ofType('@@redux-form/CHANGE')
        .filter(action => action.meta.field === "userName")
        .filter(action => (!utility.validation.lengthMin6(action.payload) && !utility.validation.userName(action.payload)))
        .debounceTime(500)
        .mergeMap(action =>
            Observable.ajax({
                url: `${apiUrl}/auth/validations/v1`,
                method: 'POST',
                body: JSON.stringify({
                    type: 'user-name',
                    value: action.payload
                }),
                headers: {
                    'Content-Type': 'text/plain'
                },
                crossDomain: true
            })
            .map(data => {
                const previousErrors = store.getState().form.signUp.asyncErrors;

                if (data.response === 'true' || data.response === true){
                    return {
                        type: "@@redux-form/STOP_ASYNC_VALIDATION",
                        meta:{
                            field: "userName",
                            form: "signUp",
                            touch: true
                        },
                        error: true,
                        payload: Object.assign({}, previousErrors, { userName : "b591d5f.0450d1b.76ae7b1.d" })
                    }
                } else {
                    return {
                        type: "@@redux-form/STOP_ASYNC_VALIDATION",
                        meta:{
                            field: "userName",
                            form: "signUp",
                            touch: true
                        },
                        error: false,
                        payload: previousErrors
                    }
                }
            })
            .startWith({
                type: "@@redux-form/START_ASYNC_VALIDATION",
                meta:{
                    field: "userName",
                    form: "signUp"
                }
            })            
            .startWith({
                type: "@@redux-form/BLUR",
                meta:{
                    field: "userName",
                    form: "signUp",
                    touch: true
                }
            })            
            .catch(error => Observable.of({
                type: "@@redux-form/STOP_ASYNC_VALIDATION",
                meta:{
                    field: "userName",
                    form: "signUp"
                }
            }))
        )
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM