preface

  • VueCompositionApi for React — Plain-design-Composition;
  • In the front-end community, the discussion between VueCompositionApi and React Hook is extremely fierce. There are different sides, some are neutral, some are on the fence and don’t know what to learn, and some are like xiaobi, who learn a little bit on both sides. After all, we are making money, we don’t have to deal with it. React development will have exactly the same VueCompositionApi development experience, provided it uses JSX instead of THE SFC template.

Nonsense not to say, directly on the talent;

The installation

Installing a plug-in

The key to using plain-design-composition (PDC) in an existing React application is to configure Babel with a compiler plug-in, as shown in the following example:

const JSXModel = require('plain-design-composition/plugins/babel-plugin-react-model')
// babel.config.js or.babelrc
module.exports = {
    plugins:[
        JSXModel,
    ],
}
Copy the code
  • This plug-in is used to compile V-models in JSX code, such as syntax sugarv-model={state.name}Will be compiled intomodelValue={state.name}As well asonUpdateModelValue={val=>state.name=val}In fact,onUpdateModelValueIn the code is a bit more complex, here is just a brief example;
  • Multi-value bindings, such as writing to a component at the same time:
    • v-model-start={ state.formData.startDate }
    • v-model-end={ state.formData.endDate }
  • This multiple value is then compiled into the following four properties:
    • start={ state.formData.startDate }
    • onUpdateStart={ val => state.formData.startDate = val }
    • end={state.formData.end}
    • onUpdateEnd={ val => state.formData.endDate = val }

This plug-in can be understood as the vue JSX compiled plug-in super scaled down version, of course, also super scaled down ………… ;

Build in Vite

This paper uses Vite to build a React application using PDC as an example. First, create a React project using Vite

Yarn Create vite // 1. Enter the project name randomly for the first time // 2. Select react template // 3. Select react-ts template // 4. Go to the project root directory to install dependencies, NPM I; Start the service: NPM run devCopy the code

Install dependencies:

yarn add plain-design-composition babel-plugin-syntax-jsx @babel/preset-react @babel/preset-typescript
Copy the code

Configure the plug-in in vite.config.ts

import {defineConfig} from 'vite'
import reactRefresh from '@vitejs/plugin-react-refresh'
// @ts-ignore
import JsxModelTransform from 'plain-design-composition/plugins/vite-plugin-react-jsx-model'

// https://vitejs.dev/config/
export default defineConfig({
    plugins: [
        JsxModelTransform(),
        reactRefresh()
    ]
})
Copy the code

You can then use PDC to write components in your application.

Other build

  • About using other build tools, such ascra.umi.vue-cli(Yes, vue-CLI can also be used to build react applications.)Plain-design is quick to get started;
  • Or if you don’t even have a cup of tea and want to get started, you can create a new HTML file and paste the code in this document to get started.

usage

Basic usage

Define a group using designComponent, such as implementing a stepper component that supports bidirectional binding of numeric variables

const DesignNumber = designComponent({
    props: {
        modelValue: {type: Number}},emits: {
        onUpdateModelValue: (val? :number) = > true.onAddNum: (val: number) = > true.onSubNum: (val: number) = > true,},setup({props, event}) {

        const {emit} = event

        const handler = {
            onClickAdd: () = > {
                const val = props.modelValue == null ? 1 : props.modelValue + 1
                emit.onAddNum(val)
                emit.onUpdateModelValue(val)
            },
            onClickSub: () = > {
                const val = props.modelValue == null ? 1 : props.modelValue - 1
                emit.onSubNum(val)
                emit.onUpdateModelValue(val)
            },
        }

        return () = > (
            <div>
                <button onClick={handler.onClickSub}>-</button>
                <button>{props.modelValue == null ? 'N' : props.modelValue}</button>
                <button onClick={handler.onClickAdd}>+</button>
            </div>)}})// Used in the parent component
export const DemoPage = designPage(() = > {
    const state = reactive({
        count: 123
    })
    return () = > <>
        <h1>Hello world:{state.count}</h1>
        <DesignNumber
            v-model={state.count}
            onAddNum={val= >console.log('add', val)} onChange={val => console.log('get change value', val, val? .toFixed(0))} /></>
})

const App = () = > <>
    <div className="App">
        <DemoPage/>
    </div>
</>

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>.document.getElementById('root'))Copy the code
  • Those of you who remember can see that. ThisDesignNumberComponent of the source code, with small series before an articleGive defineComponent enchantsIn theDesignNumberThe source code for the component is identical. The only difference is that the React component is the current one, and the Vue3 component in the other article;

Component options

All of the attributes are listed below, either in the PDC documentation or in this nuggets article: Enroping defineComponent, which includes a video explaining how each attribute is used. All properties currently function the same as plain-UI-Composition, except that they currently run in the React application.

  • name
  • provideRefer
  • inheritAttrs
  • props
  • emits
  • setup
  • expose
  • slots
  • scopeSlots

React Hook

  • DesignComponent returns a React Hook component;
  • Although the CompositionApi is recommended in the designComponent, the CompositionApi does not solve all scenarios, so the PDC exposes a code calleduseHookOnDesignA function, can be implemented in CompositionApi at the same time using Hook function SAO operation; See the following example:
import {useEffect, useRef} from 'react'
import {designPage, onBeforeUpdate, onUpdated, reactive, useHooksOnDesign, useRefs} from 'plain-design-composition'

export default designPage(() = > {

  const {refs, onRef} = useRefs({button: HTMLButtonElement})
  const state = reactive({
    num: 0,
  })

  onBeforeUpdate(() = > {
    console.log('before update:', !refs.button ? 'button not mounted' : refs.button.innerText)
  })
  onUpdated(() = > {
    console.log('updated:', !refs.button ? 'button not mounted' : refs.button.innerText)
  })

  const hookData = useHooksOnDesign(() = > {
    const count = useRef(0)
    console.log('on hook:', !refs.button ? 'button not mounted' : refs.button.innerText)
    useEffect(() = > {
      count.current++
      console.log('useEffect:', !refs.button ? 'button not mounted' : refs.button.innerText)
    })
    /* The data returned from the hook can also be used for rendering */
    return {
      count
    }
  })
  console.log(hookData)
  return () = > (
    <div>
      <h4>hook data count: {String(hookData.current.count.current)}</h4>
      <button ref={onRef.button} onClick={()= >State.num ++}> counter: {String(state.num)}</button>
    </div>)})Copy the code

Custom Composition hook functions

In the case of using PDC in Taro, taro exposes a function called usePullDownRefresh that listens for a page’s pull-down refresh event in a hook component. Now you can wrap a Composition hook function based on this hook function, as shown in the following example:

import {usePullDownRefresh, stopPullDownRefresh} from '@tarojs/taro'

const onPullDownRefresh = (fn: () => void) = > {
  // eslint-disable-next-line
  useHooksOnDesign(() = > {
    usePullDownRefresh(fn)
  })
}

export default designPage(() = > {
  const state = reactive({
    count: 100
  })
  onPullDownRefresh(() = > {
    console.log('Pull refresh', Button, View)
    stopPullDownRefresh()
  })
  return () = > <>
    <View>
      Hello world
    </View>
  </>
})
Copy the code

OnMounted hook function

export const onMounted = createHookFunction('onMounted', (cb: () = > (void | (() = > void) | any)) => {
    useHooksOnDesign(() = > {
        useEffect(() = > {
            const returnValue = cb()
            return typeof returnValue === "function" ? returnValue : undefined}, [])})})Copy the code

other

The recorded video mentioned at the end of this article also demonstrates how to use the ReActivity API to create a super-simple state-sharing mechanism. And a simple internationalization plug-in in React with less than 30 lines of code; Here is sample code for implementing a multilingual internationalization Api using the ReactivityApi:

import {reactive} from "plain-design-composition";

export const intl = (() = > {
    const state = reactive({locale: {} as Record<string.any>})
    const get = (keyString: string) = > {
        return ({
            d: (defaultString: string) :string= > {
                const keys = keyString.split('. ')
                const len = keys.length
                let obj = state.locale
                for (let i = 0; i < keys.length; i++) {
                    const key = keys[i];
                    if (i === len - 1&&!!!!! obj &&typeof obj[key] === "string") {
                        return obj[key]
                    }
                    if(! obj) {return defaultString
                    }
                    obj = obj[key]
                }
                return defaultString
            },
        })
    }
    const setLocal = (language: any) = > state.locale = language
    return {
        get, setLocal
    }
})()

// Use intL multilingual sample code
export const DemoIntl = designPage(() = > {
    return () = > <>
        <h1>{intl.get('order.detail.title').d(' default order detail title')}</h1>
        <h1>Intl.get (' order.detail.subtitle ').d(' default order detail.subtitle ')}</h1>

        <button onClick={()= >Intl. SetLocal ({order: {detail: {title: 'Chinese title,},},})} > Chinese</button>
        <button onClick={()= > intl.setLocal({
            order: {
                detail: {
                    title: 'title',
                    subTitle: 'sub title',
                },
            },
        })}>English
        </button>
    </>
})
Copy the code
  • In this example, there are both Chinese and English language packages. No language packages are used when the page is initialized, so the title and subtitle positions display the default text:
    • Default order details big title
    • Default order details subheading
  • After switching to English, the display is:
    • title
    • sub title
  • After switching to Chinese, it will be displayed as:
    • Chinese title
    • Default order detail subTitle (default display text will be used because order.detail.subTitle is not matched in the Chinese language package)

conclusion

  • Xiaobian has recorded a video explaining some of the examples in this article: Coming! VueCompositionApi For React!
  • The availability of PDC is currently supported by component libraries,plain-designThe React component library is based on the PDC implementation. It covers most of the common components and their functions. The next article will introduce the React component library. And the interesting thing is,plain-designComponent library source and Vue3 component libraryplain-uiSource code similarity of 95%;
  • The learning process of VueCompositionApi For React can be divided into three parts. The first part is to learn how to use VueCompositionApi, accounting For about 97%, and then learn to use itplain-ui-compositionThe cost of learning is 2%, and the last one isplain-design-composition, learning cost accounted for 1%;
    • VueCompositionApi;
    • Plain – UI – composition;
    • Plain – design – composition;
    • These three belong to an inclusive relationship, that is, PUC has 2% more knowledge points than VCA, PDC has 1% more knowledge points than PUC.
  • Some students may ask, I already know how to use Vue, how long will it take to learn React development? Now you have learned how to develop Vue with PDC. You can’t be a React master, but at least common React functions and components can be completed more easily. Now you can roll out other React developers.
  • Students learning React can also try VueCompositionApi to experience different development experience besides React Class and React Hook.
  • Before making this library, Xiaobian also researched other ReactCompositionApi solutions, but could not find a suitable library in his mind. Ideally, the ReactCompositionApi should be roughly the same as the Vue positionAPI, which can reduce not only the learning cost, but also the conversion cost between the Vue component and the React component. I’m sure you’ve seen or are working on a similar ReactCompositionApi library, so don’t hide it, and take a look at some of the more interesting features. .
  • Taro’s Vue3 and React version component library are being prepared to fully verify the feasibility of CompositionApi. There are plans to support the use of VueCompositionApi in ReactNative in the future. If this goes well, then SFC can be considered to develop React applications. Therefore, the ultimate goal is to use Vue SFC to develop ReactNative;