首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Redux/Redux-saga窗体架构优化

Redux/Redux-saga窗体架构优化
EN

Code Review用户
提问于 2019-10-31 16:52:18
回答 1查看 60关注 0票数 2

我正在设计这个在React/Redux/Saga中处理的很好的表单,我很担心它可能不会被优化。所以我决定问你你是怎么想的

首先,我不会详细说明如何规范json-s的结构,因为这篇文章会变得很大,所以我的redux状态是如何在FORM/INIT上初始化的:

代码语言:javascript
复制
form: {
  formName: {
    fields: { //this is were I save my form definition, for rendering purposes
      section1: {
        children: {
          textInput: {
            id: 'textInput',
            name: 'Name',
            type: 'text',
            validations: [
              {
                type: 'required',
                message: 'This field is required!'
              }
            ]
          }
        }
      }
    },
    model: {
      path: 'section1.children.textInput',
      value: 'Some value',
      isTouched: false,
      activeErrorState: {
        hasError: false,
        message: ''
      }
    }
  }
}

基本上,对于“速度”(可能不是这样的)。我将我的值/活动错误状态/标志与我的定义分开。此外,我还对组件使用的“节”、“组”、"formGroup“之类的模型和表示类型进行了简化,这些类型从”字段“定义中生成表单。另外,我有一个“路径”键,在我的头脑中,它帮助我更快地浏览“字段”树:)在本例中,它只是嵌套的3个级别,但在我的实际世界中,我有时有多达10个层次的深度。

在我的代码中,我担心的是。

这是一个传奇,在我表单字段的每一个变化中都会触发:

代码语言:javascript
复制
function* changeFormField(action) {
  // selects the redux store
  const store = yield select();
  // the payload have the name of the form, the name of the field and the value that need to get changed in the redux store (the model part of my form)
  const { formName, fieldName, value } = action.payload;
  // finding the form's fields definition and model is quite easy:
  const { fields, model } = store.form[formName];
  // I need to search the whole fields three to find the deeply nested field name, so that I can get it's validations definitions:
  const fieldDefinition = findInObjectByString(fields, model[fieldName].path);
  // I have a function that creates validation functions based on the validation definitions
  const validations = getValidations(fieldDefinition.validations);
  // I check if the new value is correct or not
  const runValidationsResult = runValidations(fieldName, value, validations);
  // this line triggers an action that updates the model.
  yield put(
    Actions.updateFormField(
      formName,
      fieldName,
      value,
      runValidationsResult
    )
  );
}

正如您所看到的,我需要遍历这个findInObjectByString函数,它为每个"onChange“上的验证定义浏览”字段“三个。

代码语言:javascript
复制
export const findInObjectByString = (nestedObject, string) => {
  // I clone the nested object, because I am afraid of mutations :)
  let clonedNestedObject = deepclone(nestedObject);
  // strip the string just in case
  string = string.replace(/\[(\w+)\]/g, '.$1');
  // remove a possible first '.' just in case
  string = string.replace(/^\./, '');
  // split the string into array of keys to iterate and search the three
  const pathArray = string.split('.');

  // eslint-disable-next-line no-plusplus
  for (let i = 0, n = pathArray.length; i < n; ++i) {
    const k = pathArray[i];
    if (k in clonedNestedObject) {
      clonedNestedObject = clonedNestedObject[k];
    } else {
      return;
    }
  }
  // eslint-disable-next-line consistent-return
  return clonedNestedObject;
};

我还需要再使用一次(获取字段的类型),当我将对象扁平化时,这样我就可以将它发送到后端:

代码语言:javascript
复制
export const flattenFormModel = (formObject) => {
  const { fields, model } = formObject;

  // this is a reduce function that takes a flat model and flattens it even more :D because BE has specific needs as it comes to how it takes the values, so I need to make some small modifications to my model and send it away:
  return Object.keys(model).reduce((acc, cur) => {
    let currentValue = model[cur].value;
    const fieldDefinition = findInObjectByString(fields, model[cur].path);

    // BE specific things, is why this is needed :)
    if (fieldDefinition.type === FIELD_TYPES.DROPDOWN && currentValue) {
      currentValue = currentValue.value;
    }

    // BE specific things, is why this is needed :)
    if (fieldDefinition.type === FIELD_TYPES.DYNAMIC && currentValue) {
      currentValue = currentValue.map((item) => {
        if (item.newField) {
          delete item.newField;
          return {
            ...item,
            id: 0
          };
        }
        return item;
      });
    }

    return {
      ...acc,
      [cur]: currentValue
    };
  }, {});
};

现在在我的直觉里,我觉得这不是一个很好的方法。我发现它搜索太多了(即使它是散列3,我还是按键访问它)。我也在考虑在模型中添加验证和类型,但这不意味着不需要字段/模型分离吗?

但是,需要考虑的一件事是,be完全不知道我的表单的结构。它向我发送初始模型,如平面结构:{name: value},{name:value}。

请帮助其他开发人员成为更好的代码编写者:)

10倍多!

EN

回答 1

Code Review用户

发布于 2019-11-01 21:15:29

您必须以当前的方式进行搜索的原因是您的redux存储非常嵌套。把它压平,这会使事情变得容易得多。在具有自己独特的id的数据结构中拥有所有文本输入,而不管它属于哪个表单或区段。

textfield不需要“知道”它属于哪个表单或部分。你把它变成了你商店另一个方面的工作。我更喜欢JavaScript Maps,但我们非常欢迎您使用对象。

创建专门用于跟踪哪些节包含哪些窗体以及哪些文本字段属于哪个部分的键。

当您需要访问输入时,只需直接获取文本字段的id即可。

一些类似于此的东西。模型只需要知道身份。不是对象嵌套结构。

代码语言:javascript
复制
{

forms: new Map(
    [
        'form1',
        ['section1', 'section2' //...]
    ]
)

fields: new Map(
    [
        'section1',
        ['textInput', 'otherTextInput']
    ]
)

textInputs: new Map(
    [
        'textInput',
        {
            id: 'textInput',
            name: 'Name',
            type: 'text',
            validations: [
              {
                type: 'required',
                message: 'This field is required!'
              }
            ]
        }
    ],
    [
        'otherTextInput',
        {
            id: 'otherTextInput',
            name: 'Name',
            type: 'text',
            validations: [
              {
                type: 'required',
                message: 'This field is required!'
              }
            ]
        }
    ]
)

model: {
    path: 'textInput',
    value: 'Some value',
    isTouched: false,
    activeErrorState: {
      hasError: false,
      message: ''
    }
  }
}
```
代码语言:javascript
复制
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/231621

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档