DEV Community

幻魂
幻魂

Posted on

Hello, concent, hello, composition for react.

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.

Top comments (0)