DEV Community

loading...

Hello, concent, hello, composition for react.

fantasticsoul profile image 幻魂 ・3 min read

funny setup

Hello dear react developers, I'm so proud to announce that setup is really a cool feature for code structure,I have used it to develop many basic components in my react app.

A very very simple component can be:

You can edit it on CodeSandbox:

With setup, code can be more efficiently organized and reused, hope you can take a little time to understand it, and you will get huge profits in the development of react .

A form

Let us write a form with setup

import React from 'react';
import PropTypes from 'prop-types';
import { Form, Button, Radio } from 'antd';
import { useConcent } from 'concent';
import * as util from './_util';

const { Item: FormItem } = Form;
const { Group: RadioGroup, Button: RadioButton } = Radio;
const { getFieldTypeMaker } = util;

const cu = {
  formItemLayout: (n) => {
    return n.formLayout === 'horizontal'
      ? { labelCol: { span: 4 }, wrapperCol: { span: 14 } }
      : null;
  },
  buttonItemLayout: (n) => {
    return n.formLayout === 'horizontal'
      ? { wrapperCol: { span: 14, offset: 4 } }
      : null;
  },
};

const setup = ctx => {
  ctx.initState({ formLayout: ctx.props.layout || 'horizontal', loading: false });

  ctx.computed(cu);

  ctx.on('cancelFormBtnLoading', () => {
    ctx.setState({ loading: false });
  });

  const onLayoutChange = (e) => {
    ctx.setState({ formLayout: e.target.value });
  }

  let renderLayoutControl = () => '';
  if (ctx.props.dynamicLayout) {
    renderLayoutControl = () => (
      <FormItem label={ctx.props.layoutFieldLabel || 'Form Layout'} style={{ marginBottom: '10px' }}>
        <RadioGroup value={ctx.state.formLayout} onChange={onLayoutChange}>
          <RadioButton value="horizontal">Horizontal</RadioButton>
          <RadioButton value="vertical">Vertical</RadioButton>
          <RadioButton value="inline">Inline</RadioButton>
        </RadioGroup>
      </FormItem>
    );
  }

  const onValuesChange = (changed) => {
    console.log(changed);
    if (ctx.props.onValuesChange) ctx.props.onValuesChange(changed);
  };

  const onFinish = (values) => {
    console.log(values);
    if (ctx.props.onFinish) {
      ctx.props.onFinish(values);
      ctx.setState({ loading: true });
    }
  };

  const UIFields = ctx.props.fields.map((f, idx) => {
    const { type, options } = f;
    const makeFn = getFieldTypeMaker(type);
    return makeFn(options);
  });

  const resetBtn = ctx.props.resetBtn;
  let UIResetBtn = '';
  if (resetBtn !== undefined) {
    const onReset = () => ctx.extra.form.resetFields();
    const btnLabel = typeof resetBtn !== 'string' ? 'Reset' : resetBtn;
    UIResetBtn = (
      <Button htmlType="button" onClick={onReset}>
        {btnLabel}
      </Button>
    );
  }

  let UIFillBtn = '';
  const { fillBtn, fillValues } = ctx.props;
  if (fillBtn !== undefined) {
    const onFill = () => {
      if (!fillValues) {
        return alert('请设置欲填充的默认值');
      }
      ctx.extra.form.setFieldsValue(fillValues);
    };
    const fillBtnLabel = typeof fillBtn !== 'string' ? 'Fill form' : fillBtn;
    UIFillBtn = (
      <Button htmlType="button" onClick={onFill}>
        {fillBtnLabel}
      </Button>
    );
  }

  return {
    renderLayoutControl,
    UIFields,
    UIResetBtn,
    UIFillBtn,
    onValuesChange,
    onFinish,
  }
}

/**@typedef {import('types/store').CtxDeS<{}, 
 * {formLayout:string}, 
 * import('concent').SettingsType<typeof setup>,
 * import('concent').ComputedValType<typeof cu>
 * >} Ctx */

  /**
 * @param {object} props
 * @param {Array<FieldInput | FieldInputGroup>} props.fields - 表单字段描述对象
 * @param {(changedValues:any)=>void} [props.onValuesChange] - 字段值改变时的回调
 * @param {(values:any)=>void} [props.onFinish] - 提交表单时的回调
 * @param {'horizontal'|'vertical'|'inline'} [props.layout='horizontal'] - 布局模式(水平、垂直、行内)
 * @param {boolean} [props.dynamicLayout=false] - 是否动态布局
 * @param {string} [props.layoutFieldLabel='Form Layout'] - 布局字段文案
 * @param {string} [props.submitBtnLabel='Submit'] - 提交按钮的文案
 * @param {boolean | string} [props.resetBtn=false] - 是否需要重置按钮,传递string表示重新默认文案
 * @param {boolean | string} [props.fillBtn=false] - 是否需要填充表单按钮,传递string表示重新默认文案
 * @param {object} [props.fillValues] - 设置需要填充的默认值
 */
const EasyForm = (props) => {
  const [form] = Form.useForm();

  /**@type Ctx */
  const ctx = useConcent({ setup, props, extra: { form } });
  const {
    state: { formLayout, loading },
    refComputed: { formItemLayout, buttonItemLayout },
    settings: { renderLayoutControl, UIFields, UIResetBtn, UIFillBtn, onValuesChange, onFinish }
  } = ctx;

  return (
    <div>
      <Form
        {...formItemLayout}
        layout={formLayout}
        form={form}
        onFinish={onFinish}
        initialValues={{
          layout: formLayout,
        }}
        onValuesChange={onValuesChange}
      >
        {renderLayoutControl()}
        {UIFields}
        <Form.Item {...buttonItemLayout}>
          <Button type="primary" htmlType="submit" loading={loading}>{props.submitBtnLabel || 'Submit'}</Button>
          {UIResetBtn}
          {UIFillBtn}
        </Form.Item>
      </Form>
    </div>
  );
}

EasyForm.propTypes = {
  fields: PropTypes.array.isRequired,
}

export default React.memo(EasyForm);

here is the online form example

What is concent

concent is a build-in dependency collection, predictable、zero-cost-use、progressive、high performance's react develop framework.
❤ know more about concent ^_^

Edit js project on CodeSandbox
https://codesandbox.io/s/concent-guide-xvcej

Edit ts project on CodeSandbox
https://codesandbox.io/s/concent-guide-ts-zrxd5

If you have any questions about concent, you can post issues in git repo.

Discussion (0)

Forem Open with the Forem app