Giter VIP home page Giter VIP logo

akryl-core's Introduction

Akryl

Kotlin wrapper around ReactJS.

With akryl, you can write simple and idiomatic Kotlin code that will be converted into React components. For example, you can rewrite this JavaScript code:

const App = ({name}) => {
    return <div>Hello, {name}!</div>;
}

in Kotlin using akryl:

fun App(name: String) = component {
    div(text = "Hello, $name!")
}

Install

There are two options to install Akryl:

  • Starter project - a convenient way for beginners.
  • Manual install - if you want full control over the project.

Starter Project

If you don't want to set up the project yourself, you can clone akryl-frontend-starter repository:

git clone https://github.com/akryl-kt/akryl-frontend-starter
cd akryl-frontend-starter
./run.sh
# open http://localhost:8080 when build completes

Manual Install

To add Akryl to an existing project, follow the steps below. This instruction assumes that you already have a Kotlin/JS project configured with Gradle.

Akryl library consists of several pieces:

In most cases, you need to install all of them.

  1. Add jcenter repository:
repositories {
    jcenter()
    ...
}
  1. Add these dependencies into your build.gradle file:
kotlin {
    sourceSets {
        main {
            dependencies {
                ...
                // kotlin dependencies
                implementation "io.akryl:akryl-core:0.+"
                implementation "io.akryl:akryl-dom:0.+"
                implementation "io.akryl:akryl-redux:0.+"

                // babel-plugin-akryl dependencies
                implementation npm("babel-loader", "8.0.6")
                implementation npm("@babel/core", "7.7.7")
                implementation npm("@babel/preset-env", "7.7.7")
                implementation npm("babel-plugin-akryl", "0.1.1")
                // react dependencies
                implementation npm("react", "16.12.0")
                implementation npm("react-dom", "16.12.0")
                implementation npm("redux", "4.0.5")
                implementation npm("react-redux", "7.1.3")
            }
        }
    }
}
  1. Add babel.js file into webpack.config.d directory to load babel-plugin-akryl:
config.module.rules.push({
  test: /\.m?js$/,
  exclude: /(node_modules|bower_components|packages_imported)/,
  use: {
    loader: 'babel-loader',
    options: {
      presets: ['@babel/preset-env'],
      plugins: [
        ['babel-plugin-akryl', {production: !config.devServer}],
      ],
    }
  }
});
  1. Add src/main/resources/index.html file:
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Akryl Frontend Starter</title>
    <link rel="stylesheet" href="index.css">
</head>
<body>
    <div id="app"></div>
    <script type="text/javascript" language="JavaScript" src="<jour-project-name>.js"></script>
</body>
</html>
  1. Add src/main/kotlin/App.kt file:
import io.akryl.component
import io.akryl.dom.html.Div
import react_dom.ReactDom
import kotlin.browser.document

fun app() = component {
  div(text = "Hello, World!")
}

fun main() {
  ReactDom.render(app(), document.getElementById("app"))
}
  1. Run the project:
./gradlew run --continuous

Documentation

akryl-core provides basic React features:

  • Components
  • Context
  • Hooks

To use JSX-like syntax you need to install akryl-dom library.

Components

With Akryl you can use only hooks API and functional components. To create a component you must define a function, that takes props as arguments and returns a virtual DOM element. It is important to wrap the function body into a component function call. It tells the babel-plugin-akryl to convert a simple Kotlin function into a React component.

Example:

fun Calc(a: Int, b: Int) = component {
    div(text = "Sum = ${a + b}")
}

The Calc is a React component, that accepts a and b in props and returns div element. Here is the equivalent component in JSX:

export const Calc = ({a, b}) => {
    return <div>Sum = {a + b}</div>;
};

and in TSX:

export interface CalcProps {
    a: number;
    b: number;
}

export const Calc = ({a, b} : CalcProps) => {
    return <div>Sum = {a + b}</div>;
};

In Akryl you don't need to wrap props into an interface or in a class - just pass them as function arguments.

You can call a component function from any place in code. There is no restriction to use a component only inside another component.

Example:

// Akryl
val element = Calc(a = 10, b = 20)
// JSX
const element = <Calc a={10} b={20} />;

If your component is pure, you can use memo instead of component function. It has the same effect as in React: it will prevent a component from re-render if its props are not changed.

Hooks

Akryl has common hooks from React:

All hooks have receiver argument of type ComponentScope, that prevents usage outside of a component at compile time.

// will compile
fun counter() = component {
    val (state, setState) = useState(0)
}

// will not compile: ComponentScope receiver is not provided
val (state, setState) = useState(0)

To create a custom hook, write a function that has the ComponentScope receiver parameter:

fun ComponentScope.useRenderCount(): Int {
    val ref = useRef(0)
    ref.current += 1
    return ref.current
}

JavaScript Interop

Akryl components can accept JS components as children and vice versa. There can be a component tree that contains an arbitrary mix of Akryl and JS components.

To use an existing React library, declare the library using @JsModule and write helper functions to use components in a convenient way. For example, let's create a wrapper for blueprintjs button:

// library declaration

@JsModule("@blueprintjs/core")
@JsNonModule
external object Blueprint {
    val Button: Component<dynamic>
}

// helper function for button

fun bpButton(
    onClick: (() -> Unit)? = undefined,
    children: List<ReactElement<*>> = emptyList()
) = React.createElement(
  type = Blueprint.Button,
  props = json(
    "onClick" to onClick
  ),
  children = *children.toTypedArray()
)

// usage in Akryl

fun app() = component {
    bpButton(
        onClick = { window.alert("Hello, World!") },
        children = listOf(text("Click me!"))
    )
}

Comparison with kotlin-react

There are two options to create a component in kotlin-react.

  1. Class API
interface GreetingProps : RProps {
    var name: String
}

class Greeting : RComponent<GreetingProps, RState>() {
    override fun RBuilder.render() {
        div {
            +"Hello, ${props.name}!"
        }
    }
}

fun RBuilder.greeting(name: String = "John") = child(Greeting::class) {
    attrs.name = name
}
  1. Functional API
interface GreetingProps : RProps {
    var name: String
}

val greeting = functionalComponent<GreetingProps> { props ->
    div {
        +"Hello, ${props.name}!"
    }
}

fun RBuilder.greeting(name: String = "John") = child(greeting) {
    attrs.name = name
}

Akryl has only a functional API.

fun greeting(name: String = "John") = component {
    div(text = "Hello, $name!")
}

Differences between kotlin-react and akryl:

  • In both options of kotlin-react, you need to create a props class, a component body, and a helper function. In akryl, you only need to create a single function.
  • The functional component of kotlin-react will be anonymous. It will not have a name in React DevTools, so it will be harder to debug.
  • attrs are not enforcing required props.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.