показывать форму в динамическом столбце при итерации

#javascript #reactjs

#javascript #reactjs

Вопрос:

У меня длинная форма, которая имеет столбец смешанного типа. Я имею в виду, что какое-то поле будет иметь ширину 100%, а какое-то поле будет составлять около 33%, чтобы я мог отображать 3 поля в столбце и так далее. Это я мог бы сделать без итерации, но как это можно сделать, если поля отображаются с итерацией, чтобы избежать повторения кода?Я также создал изолированную среду, и я не использую сторонний css-фреймворк, такой как bootstrap, просто гибкий или, может быть, сетка будет работать.

Вот как я пытался:

 const formFields = [
  { id: 1, name: "first_name", component: TextField, label: "First Name" },
  { id: 1, name: "last_name", component: TextField, label: "Last Name" },
  { id: 1, name: "age", component: TextField, label: "Age" },
  { id: 1, name: "city", component: TextField, label: "City" },
  { id: 1, name: "state", component: TextField, label: "State" },
  { id: 1, name: "country", component: TextField, label: "Country" }
];

const FlexibleForm = () => {
  return (
    <React.Fragment>
      <Form onSubmit={() => console.log("something")}>
        <FlexRow>
          <FlexColumn size={12}>
            {formFields.map(({ id, name, label, component }) => {
              return (
                <Field
                  key={id}
                  name={name}
                  label={label}
                  component={component}
                />
              );
            })}
          </FlexColumn>
        </FlexRow>
        <h2>Another without iteration</h2>
        <FlexRow>
          <FlexColumn size={6}>
            <Field name="first_name" label="First Name" component={TextField} />
          </FlexColumn>
          <FlexColumn size={6}>
            <Field name="last_name" label="Last Name" component={TextField} />
          </FlexColumn>
        </FlexRow>
        <FlexRow>
          <FlexColumn size={12}>
            <Field name="age" label="Age" component={TextField} />
          </FlexColumn>
        </FlexRow>
        <FlexRow>
          <FlexColumn size={4}>
            <Field name="city" label="City" component={TextField} />
          </FlexColumn>
          <FlexColumn size={4}>
            <Field name="state" label="State" component={TextField} />
          </FlexColumn>
          <FlexColumn size={4}>
            <Field name="country" label="Country" component={TextField} />
          </FlexColumn>
        </FlexRow>
      </Form>
    </React.Fragment>
  );
};

export default reduxForm({
  form: "form"
})(FlexibleForm);

export const FlexRow = styled.div`
  display: flex;
  div {
    margin-right: 10px;
  }
`;

export const FlexColumn = styled.div`
  width: ${props => (props.size / 12) * 100}vw;
`;
  

Вот ссылка на codesandbox https://codesandbox.io/s/l7lm1qp0pq

Комментарии:

1. В чем вопрос?

2. теперь вопрос выделен жирным шрифтом. Как я могу отображать поля в разных столбцах с помощью итерации, что я делал без использования итерации?

3. Возможно, в вашем FlexRow компоненте вы можете добавить некоторые реквизиты, такие как массив объектов, [{name: "city", "label": "city", "component": <TextField />}, {name: "state", "label": "state", "component": <TextField />}, .....] а затем создать условие для проверки количества элементов в массиве, если это три элемента, затем создайте 3 гибких столбца размером 4. Допустим, вы вызываете свой реквизит itemsInRow , затем FlexRow вы можете написать что-то вроде`this.props.itemsInRow.map( () => <Размер гибкой колонки={Math.round(12/this.props.itemsInRow.length)}> и т.д.

4. можете ли вы воспроизвести пример с вашей концепцией, разветвляя мой код из песочницы, пожалуйста?

5. Ниже приведено несколько решений, но я хотел бы перефразировать великого Иэна Малкольма: «Вы были так озабочены тем, можете ли вы это сделать, что вы не задумывались, стоит ли вам это делать». Сохраняет ли этот код «динамическим», решая что-либо, или просто усложняет ваш код?

Ответ №1:

Это <FlexRow> компонент

 const FlexRow = props => {
 return (
   <div style={{ display: "flex" }}>
    {props.elements.map((element, index) => {
       const obj = element.component;
       return (
         <FlexColumn key={index} size={Math.round(12 / props.elements.length)}>
           <Field
             name={element.name}
             label={element.label}
             component={obj[Object.keys(obj)[0]]}
           />
         </FlexColumn>
       );
    })}
  </div>
 );
};
  

Это <FlexColumn> компонент

 const FlexColumn = styled.div`
   width: ${props => (props.size / 12) * 100}vw;
   margin-right: 10px;
`;
  

Ваш <FlexibleForm> должен выглядеть так :

 const FlexibleForm = () => {
    return (
        <React.Fragment>
          <Form onSubmit={() => console.log("something")}>
            <FlexRow
              elements={[
                { name: "first_name", label: "First Name", component: {TextField} },
                { name: "last_name", label: "Last Name", component: {TextField} }
              ]}
            />
            <FlexRow
              elements={[{ name: "age", label: "Age", component: {TextField} }]}
            />
            <FlexRow
              elements={[
                { name: "city", label: "City", component: {TextField} },
                { name: "state", label: "State", component: {TextField} },
                { name: "country", label: "Country", component: {TextField} }
              ]}
            />
          </Form>
        </React.Fragment>
      );
    };
  

Компонент <FlexRow> будет зацикливаться внутри своих реквизитов elements и создаст a <FlexColumn> с хорошим размером и хорошими атрибутами.
В общем, он выполнял цикл внутри реквизита elements , который представляет собой массив, и возвращал размер (12, деленный на количество имеющихся у вас строк), вы можете изменить это значение, если хотите, с помощью простого условия, например :

element.size ? element.size : Math.round(12 / props.elements.length) и добавьте size элемент в свой elements массив

{ name: "first_name", label: "First Name", size: 6, component: {TextField} }

Затем он добавляет метку и имя. И, наконец, он добавляет выбранный вами компонент, в этом примере это <TextField>

Это позволит избежать повторения вашего кода. Вот CodeSandbox, чтобы показать вам пример!

Жаль, что я вам не помог.

Комментарии:

1. Мне нравится это решение, но я думаю, что проблема, с которой я сталкиваюсь (на самом деле, с вопросом), заключается в том, что избегание повторения кода в этом экземпляре значительно усложняет задачу. Решение, которое мне нравится больше всего, было оригинальным. он явный, его легко изменять и отлаживать, и новый разработчик, который приходит, может его прочитать..

2. @Beaulne да, я думаю, вы правы, единственная проблема, которую я вижу в его итерации, которая намного проще, чем моя, заключается в том, что он не может выбрать размер поля. Я предпочитаю использовать <Component> , и <ComponentItem> для меня это проще читать и добавлять свойства

Ответ №2:

Нет особого смысла использовать flex, если вы не используете flex-wrap.

Если вы хотите сделать это с помощью простого float:

 const formFields = [
  { id: 1, name: "first_name", component: TextField, label: "First Name",size: 6 },
  { id: 1, name: "last_name", component: TextField, label: "Last Name", size: 6 },
  { id: 1, name: "age", component: TextField, label: "Age", size: 12 },
  { id: 1, name: "city", component: TextField, label: "City", size: 4 },
  { id: 1, name: "state", component: TextField, label: "State", size: 4 },
  { id: 1, name: "country", component: TextField, label: "Country", size: 4 }
];

const Form = styled.form`
  width: 100%;
`;

const FlexColumn = styled.div`
  float: left;
  width: ${props => (props.size / 12) * 100}%;
`;

const FlexibleForm = () => (
  <React.Fragment>
    <Form onSubmit={() => console.log("something")}>
      {formFields.map(({ id, name, label, component, size }) => {
        return (
          <FlexColumn size={size}>
            <Field key={id} name={name} label={label} component={component} />
          </FlexColumn>
        );
      })}
    </Form>
  </React.Fragment>
);
  

Комментарии:

1. Работает ли это без переноса <FlexColumn> в a <FlexRow> ?

2. я не оборачиваю их