Navigation

    BaliJS
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unsolved
    • Popular
    • Talents
    • Users
    • Groups
    1. Home
    2. natserract

    natserract (@natserract)

    44
    Reputation
    45
    Posts
    35
    Profile views
    3
    Followers
    8
    Following
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    Information about natserract

    Problem Solver
    Joined
    Last Online
    Website
    github.com/natserract
    Location
    Bali
    Age
    22

    About me

    Cool links: http://rustlang.org/

    Best posts made by natserract

    • Ngoding React di Vue (include: TypeScript) πŸ”₯

      Ketika pertama kali kamu ingin belajar suatu teknologi khususnya frontend, biasanya kamu bingung mau mulai dari mana, salah satu alasannya karena kamu dihadapkan dengan banyak pilihan stack, contohnya: Vue, Angular, React, dll. Tentu saja ini membingungkan, maka dari itu supaya tahu bagaimana stack2 itu bekerja, caranya adalah harus langsung mencobanya. Yang perlu diingat semua teknologi punya pros dan consnya masing2.

      Nah, dalam tulisan ini, kita ga akan ngebahas mana yang terbaik, karena semua digunakan sesuai dengan kebutuhan, yang akan kita bahas disini adalah bagaimana para React developer bisa dengan mudah ngoding di Vue dengan kode yang mirip/sama (97%). Tulisan ini cocok buat kamu bagi para react dev yang lagi ingin bermigrasi ke vue atau sekedar mau belajar.

      So, ini perjalanan panjang! Baca doa dulu biar adem! πŸ˜ƒ

      Persiapan Project

      Pertama yang harus kita lakukan adalah mengatur project, mulai dengan membuat struktur direktori terlebih dahulu.

      1. Struktur direktori root

      Ini struktur direktori yang kita pakai dalam project ini, didalam folder komponen ada 2 folder yaitu container dan presentational. Kedua folder ini nantinya dipakai untuk membedakan mana komponen logic dan mana komponen view.

      β”œβ”€β”€ src
      | β”œβ”€β”€ assets
      | β”œβ”€β”€ components
      |   β”œβ”€β”€ container
      |   β”œβ”€β”€ presentational
      β”œβ”€β”€ redux
      | β”œβ”€β”€ action
      | β”œβ”€β”€ reducer
      β”œβ”€
      

      Kamu bisa bebas mengatur struktur direktori ini sesuai hati nurani kamu, yang penting kamu suka, nyaman dan aman.

      2. Menggunakan JSX & TypeScript

      So, mari kita mulai dengan menginstal beberapa dependensi yang diperlukan. Kita dapat melakukan ini dengan mengetikkan perintah:

      npm i --save-dev typescript babel-preset-vca-jsx
      npm i --save-dev @babel/plugin-syntax-dynamic-import @babel/plugin-transform-runtime 
      npm i --save-dev @babel/preset-typescript @types/webpack-env source-map-loader 
      npm uninstall babel-plugin-transform-runtime 
      

      Kita perlu menghapus package ini babel-plugin-transform-runtime, karena kita sudah menginstal versi yang terbaru @babel/plugin-transform-runtime

      Dan selanjutnya, kita harus mengatur beberapa konfigurasi tambahan karena beberapa packages memerlukan versi Babel yang support.

      Catatan: Kebetulan saya make boilerplate ini: Vue Webpack Template kamu bisa memilih boilerplate apa saja.

      Update babel core & babel loader

      npm i --save-dev [email protected]^7.0.0-0 [email protected]^8.0.6 
      npm i --save-dev @babel/[email protected]^7.6.4 @babel/[email protected]^7.6.3 
      

      Setelah menginstal semua dependensi, kita harus mengatur konfigurasi tambahan pada .babelrc buka file ini, dan tambahkan config .babelrc dan kita juga mengatur webpack loadernya webpack config

      Catatan: Untuk typescript loader, ada alternative lain, seperti Awesome TypeScript Loader

      Dan jangan lupa, kamu juga harus menambahkan beberapa config di .eslintrc.js

      rules: {
          'import/extensions': ['error', 'always', {
            jsx: 'never',
            ts: 'never',
            tsx: 'never'
          }],
      }
      

      Dan selanjutnya, buat file baru tsconfig.json lalu ikutin config ini tsconfig.json

      Setelah semua config ditambahkan, hooray! ini waktunya ganti extension seluruh file project kamu dari .jsx/.js ke.tsx/.ts

      Catatan: Untuk bagian kedua ini memang cukup ribet, kalo mau langsung di skip boleh, kamu bisa pake boilerplate yang saya buat Project Boilerplate

      3. Install dependensi tambahan

      npm i --save @vue/composition-api vuejs-redux redux @types/redux 
      

      Konsep Utama

      Sebagai frontend tools yang sangat populer, react dan vue memiliki fitur yang sama, seperti two-way-databinding, templating, routing, components, dan masih banyak lagi.

      Serupa tapi tak sama, ada beberapa perbedaan antara kedua tools ini, yaitu dalam hal penulisan sintaks, rendering komponen, pengelolaan kondisi dan data. Oleh karena itu, pada bagian ini kita akan mengupas satu per satu cara menerapkan pattern React di Vue.

      Komponen and Props
      Komponen adalah jenis fungsi khusus seperti fungsi JavaScript yang akan menampilkan sebuah element dan dapat digunakan sebagai bagian terpisah dan dapat digunakan kembali. Dalam merender komponen, keduanya sangat berbeda. React mendefinisikan komponen sebagai class atau fungsi, kalo Vue berdasarkan objek.

      export default createComponent({
          name: 'ComponentProps',
          props: {
              name: String,
              authorName: Array as () => string[]
          },
          setup(props) {
              return () => (
                  <div className="components-props">
                      <h2>{props.name}</h2>
                      <p>{props.authorName}</p>
                  </div>
              )
          }
      })
      

      Kita tidak perlu menggunakan template lagi, right?πŸ™‚

      render () {
        return (
            <ComponentProps 
               name="Your name here" 
               commentId={['Name1', 'Name2']} 
            />
        )
      }
      

      Render Pengkondisian
      Cara kerjanya mirip seperti pengkondisian di javascript biasa, kita bisa menggunakan if else ataupun ternary operator

      export default createComponent({
          name: 'ConditionalRendering',
          props: {
              show: Boolean
          },
          setup(props) {
              return () => props.show ? <p>True Condition</p> : <p>False Condition</p>
          }
      })
      
      render() {
         return <ConditionalRendering show={false}/>
      }
      

      Menangani Event
      Di Vue JS, saat menangani event, vue memberikan kita arahan untuk menggunakan v-on. Nah karena kita sudah menggunakan JSX, jadi kita tidak membutuhkan itu lagi, kita bisa menggunakan attribut JSX biasa seperti di React πŸ™‚

      export default createComponent({
          setup(props) {
              return () => (
                  <button onClick={props.handleButtonClick}>
                      Click Event
                  </button>
              )
          },
          props: {
              handleButtonClick: Function as () => void
          }
      })
      
      render () {
        return (
             <HandlingEvent 
                handleButtonClick={() => alert("Click event. This works!")} 
             />
        )
      }
      

      Children
      Children komponen digunakan untuk menampilkan apapun yang kamu wrap antara tag pembuka dan penutup. Untuk mengakses komponen ini, kita dapat menggunakan fungsi slots.

      export default Vue.component('Children', {
          render() {
              return (
                  <div className="children">
                      {this.$slots.default}
                  </div>
              )
          }
      })
      
      render () {
        return (
           <div className='container'>
              <Children>
                {/* what is placed here is passed as children */}
              </Children>
           </div>
        )
      }
      

      Siklus Kehidupan & Hooks

      Siklus hidup adalah metode yang mengatur tahapan siklus hidup dalam suatu komponen, dan memiliki fungsi masing-masing.

      • setup: dipanggil setelah resolusi properti awal ketika instance komponen dibuat. Dari segi siklus, ia dipanggil sebelum hooks beforeCreate.
      • onBeforeMount: fungsi yang dijalankan sebelum proses rendering dijalankan.
      • onMounted: fungsi yang dipanggil hanya sekali setelah rendering pertama selesai. Biasanya fungsi ini digunakan untuk menghandle side effect dalam operasi request ajax.
      • onUnmounted: fungsi yang dijalankan untuk menghilangkan atau menghapus komponen dari DOM.
      import {
          createComponent,
          reactive as useState,
          onBeforeMount as componentWillMount,
          onMounted as componentDidMount,
          onUnmounted as componentWillUnmount
      } from '@vue/composition-api';
      
      const LifecycleHooks = createComponent({
          setup() {
              const state = useState<{ loading: boolean, users: object }>({
                  loading: false,
                  users: []
              })
      
              componentWillMount(() => {
                  console.log("Component before mount")
              })
      
              componentDidMount(() => {
                  const API_URL = 'https://jsonplaceholder.typicode.com/users'
                  fetch(API_URL)
                      .then(res => res.json() as Promise<any>)
                      .then(data => {
                          state.users = data,
                              state.loading = !state.loading;
                      })
                      .catch((err: Error) => {
                          throw err
                      })
                  console.log("Component Mounted")
              });
      
              componentWillUnmount(() => {
                  console.log("Component Will Unmount")
              })
      
              return () => (
                  <div className="lifecycle-hooks">
                      {state.loading ? JSON.stringify(state.users) : <span>Loading...</span>}
                  </div>
              )
          }
      })
      
      export default LifecycleHooks
      
      • reactive: fungsi ini mirip dengan Vue.observable()pada Vue 2, fungsi ini mengembalikan sebuah object baru, dan mengembalikan proxy reaktif dari aslinya.
      • watch: "function expects a function" itu istilahnya. Fungsi ini melacak variabel reaktif didalam suatu komponen. Ketika nilai dari variable reaktif tersebut diganti/update, maka fungsi dijalankan kembali atau dirender ulang.
      import {
          createComponent,
          reactive as useState,
          watch as useEffect
      } from '@vue/composition-api';
      
      const LifecycleHooks = createComponent({
          setup() {
              const state = useState<{ count: number }>({
                  count: 0
              })
      
              /* => Re-run it whenever the dependencies have changed */
              useEffect(() => state.count, (nextState, prevState) => {
                  console.log(nextState, '<= this is nextState')
                  console.log(prevState, '<= this is prevState');
              })
      
              return () => (
                  <div className="lifecycle-hooks">
                      <button onClick={() => state.count++}>
                          Update Value
                      </button>
                  </div>
              )
          }
      })
      

      Redux & Vue

      Tentunya kamu pasti sudah tau apa itu Redux right?, ya! kamu jackpot! Redux adalah sebuah library state management untuk aplikasi javascript. Ga kayak vuex, redux bisa digunakan framework apapun.

      Redux mempunyai 4 konsep: reducers, actions, action creators, dan store. State pada Redux sifatnya immutable dan pure functions. Berikut adalah beberapa hal yang perlu diketahui lebih lanjut tentang redux di vue:

      Actions
      Actions adalah objek Javascript sederhana yang tugasnya adalah mengirim/mengembalikan data dari aplikasi kamu ke store. Jika diberikan perumpamaan, maka action adalah orang yang memberikan perintah untuk melakukan suatu pekerjaan dan memberikan hal-hal yang diberikan untuk dapat menunjang pekerjaan itu.

      export const INCREMENT = 'INCREMENT'
      export const DECREMENT = 'DECREMENT'
      export const RESET = 'RESET'
      
      
      export const increment = () => {
          return { 
              type: INCREMENT 
              // your payload here
          }
      }
      
      export const decrement = () => {
          return { 
              type: DECREMENT 
          }
      }
      
      export const reset = () => {
          return { 
              type: RESET 
          }
      }
      

      Reducers
      Reducers mempunyai peran sebagai penentu bagaimana keadaan aplikasi berubah sesuai dengan perintah yang diberikan lalu dikirim ke store. Kamu bisa membuat banyak reducer, lalu mengkombinasikannya menjadi satu root reducer.

      type Action = { type: 'INCREMENT' } | { type: 'DECREMENT' } | { type: 'RESET' };
      
      const Counter = (state: number = 0, action: Action) => {
          switch (action.type) {
              case 'INCREMENT': {
                  return state + 1;
              }
              case 'DECREMENT': {
                  return state - 1;
              }
              case 'RESET': {
                  return state
              }
              default: return state
          }
      }
      
      export default Counter
      

      Fungsi combineReducers untuk memanggil semua reducer yang kamu buat. Ini tentunya sangat useful:)

      import { combineReducers } from 'redux'
      import userReducer from './reducer/user.reducer'
      
      export default combineReducers({
          user: userReducer
          // your another reducer here
      })
      

      Store
      A store tempat menyimpan state/data dari aplikasi kamu. Store, memegang seluruh cabang dari aplikasi kamu. Hanya ada satu store di Redux.

      import Vue from 'vue'
      import { createStore } from 'redux'
      
      import Provider from 'vuejs-redux';
      import RootReducer from './rootReducer'
      
      const store = createStore(RootReducer);
      
      export default Vue.component('Provider', {
          render() {
              return (
                  <Provider 
                      mapStateToProps={this.mapStateToProps} 
                      mapDispatchToProps={this.mapDispatchToProps} 
                      store={store}> 
                      {this.$scopedSlots.default}
                  </Provider>
              )
          },
      
          props: ['mapStateToProps', 'mapDispatchToProps'],
      
          components: {
              Provider
          }
      })
      

      Kamu juga bisa membuat custom provider yang menerima mapStateToProps and mapDispatchToProps sebagai props and mengimport store serta meneruskannya ke setiap Provider.

      import Vue from 'vue';
      import ContextConsumer from './redux';
      import * as actions from './redux/action/user.action';
      
      import ComponentContainer from './components/container/component-wrap';
      
      export default Vue.component('App', {
        render() {
         return (
            <ContextConsumer 
                mapStateToProps={this.mapStateToProps} 
                mapDispatchToProps={this.mapDispatchToProps}>
                  {({ incrementAction, userData }) => (
                      <ComponentContainer>
                          <SingleComponent
                            value={userData.user}
                            handleClick={incrementAction} 
                          />
                      </ComponentContainer>
                  )}
            </ContextConsumer>
          )
        },
      
        components: {
          ContextConsumer
        },
      
        methods: {
          mapStateToProps(state) {
            return {
              userData: state
            }
          },
          mapDispatchToProps(dispatch) {
            return {
              incrementAction: () => dispatch(actions.increment())
            }
          }
        }
      })
      

      Higher-Order Components

      Higher-order component (HOC) adalah sebuah konsep/teknik/pattern advanced di React yang dapat digunakan terus-menerus alias (reusable). HOCs bukan bagian dari React API.

      Jika kamu paham dengan konsep higher-order functions (HOF), tentunya akan sangat mudah membuat HOC, karena HOC adalah implementasi dari HOF πŸ™‚

      import Vue from 'vue'
      
      const useDataFetchingHOC = (WrappedComponent: JSX.IntrinsicElements) => (urlParam: string) => {
          return Vue.component('HOCFetch', {
              data: () => ({
                  fetchData: null
              }),
              mounted: function() {
                  fetch(urlParam)
                      .then(response => {
                          if (!response.ok) { throw new Error(response.statusText) }
                          return response.json() as Promise<any>;
                      })
                      .then(data => this.fetchData = data)
                      .catch((err: Error) => {
                          throw err
                      })
              },
      
              render(createElement) {
                  return !this.fetchData ? createElement('span', 'Loading Fetch...') :
                      createElement(WrappedComponent, {
                          attrs: this.$attrs,
                          props: this.$props,
                          on: this.$listeners
                  })
              }
          })
      };
      
      export default useDataFetchingHOC
      
      import { createComponent } from '@vue/composition-api'
      import useDataFetchingHOC from '../presentational/hoc-component'
      
      const dataSourceUrl = "https://jsonplaceholder.typicode.com/users";
      
      const ContentSite = createComponent({
          setup() {
            return () => (
              <div className="content">
                <p>Yes, i'm in HOC</p>
              </div>
            )
          }
        })
      
      export default useDataFetchingHOC(ContentSite)(dataSourceUrl)
      
      

      Terimakasih sudah membaca!
      Terima kasih telah membaca, saya harap kamu menikmati artikel ini, dan bisa memberi inspirasi baru untuk pekerjaan kamu. Yang pasti, Vue dan React adalah tools front-end yang sangat keren, dan sangat diminati oleh banyak pengguna. Jadi, teruslah mencoba dan mempelajari hal-hal baru, dan jangan lupa selalu percaya diri!😎

      Source code: Github

      posted in Front End
    • Serba otomatis dengan shell script

      hack-like-pro-scripting-for-aspiring-hacker-part-1-bash-basics.1280x600.jpg

      Source image: nullbyte

      foto hanya pemanis/click bait

      Bagi kalian yang mau cepet, dan serba otomatis mungkin ini bisa bermanfaat buat kalian.

      Nah, shell script? fungsinya buat apa?, shell script sebenernya adalah sebuah bahasa pemrograman yang berfungsi sebagai jembatan antara user dan kernel untuk menjalankan perintah2 Unix/Linux shell.

      Fungsinya sendiri sangat banyak, salah satunya hacking, tpi disini bukan bahas hacking ya, tpi lebih ke optimisasi waktu, contohnya running multiple nodejs script untuk nge-watch scss, javascript, ataupun jalanin http server. Biasanya kita ketik manual di terminal, dengan new-tab2, contoh:

      WindowA: watch --sass
      WindowB: watch --js
      WindowC: serve --js

      Sungguh, tidak efektif bukan? Nah, dengan shell script kamu bisa dengan mudah menjalankan itu semua dengan satu kata BOOOM

      Contoh casenya kali ini adalah, ceritanya bambang lagi buat project Angular, dan dia ada requirements untuk membuat custom web component, dimana setiap component punya satu file bootstraping (contohnya seperti ini: manually bootstrap angular app )

      Struktur direktorinya seperti ini:
      .
      β”œβ”€β”€ components
      β”œβ”€β”€ button
      β”œβ”€β”€β”€β”€ button.module.ts
      β”œβ”€β”€β”€β”€ compile.ts
      β”œβ”€β”€ slider
      β”œβ”€β”€β”€β”€ slider.module.ts
      β”œβ”€β”€β”€β”€ compile.ts

      Dan isinya sekilas seperti ini:

      -> button.module.ts

      @NgModule({
        imports: [BrowserModule, ComponentModule],
        entryComponents: [ButtonComponent],
      })
      export class ButtonElementModule extends RootElementModule {
        constructor(
          injector: Injector
         ){
          super(injector, ButtonComponent, 'button');
         }
      }
      

      -> compile.ts

      enableProdMode();
      
      platformBrowserDynamic().bootstrapModule(ButtonElementModule)
      .catch(err => console.error(err));
      

      Running:

      ng run library:build:production --aot --output-path=tmp/button --main="components/button/compile.ts"
      

      Dan outputnya seperti ini:

      • runtime-es2015.js
      • runtime-es5.js
      • polyfills-es5.js
      • polyfills-es2015.js
      • main-es2015.js
      • main-es5.js

      Terus si atasan minta, itu hasil buildnya di jadiiin satu file aja, biar ga kebanyakan integrasi js file, atasan juga minta nanti dibuildnya per-component ya, terus atasan juga minta nanti file/folder ini di include in ya di build foldernya, terus atasan minta ini minta itu, hmm..

      Nah, coba bayangkan kamu melakukan itu semua manual, apalagi kalo komponennya sudah banyak? Aduh cape deh......

      Maka dari itu, kita bisa menggunakan bantuan shell script untuk mempercepat dan menyelesaikan semua proses tersebut!

      Hasil kodenya seperti ini:

      #!/bin/bash
      search_dirs=($(ls components/))
      rm -rf ./dist/library/
      mkdir ./dist/library
      
      for dir in ${search_dirs[*]}; do
          ng run library:build:production --aot --output-path=tmp/${dir} --main="components/${dir}/compile.ts"
          cat ./tmp/${dir}/{runtime,polyfills,main}-es5.js > ./tmp/${dir}.js
          cp -r ./tmp/${dir}.js ./dist/library
          rm -rf ./tmp/
      done
      

      Penjelasan kode diatas adalah dimulai dari line pertama, dimana karena kali ini kita menggunakan bash, jdi dimulai dengan #!/bin/bash

      Selanjutnya, kita nge-find direktori apa aja yang ada di folder components/, nantinya resultnya berupa array

      Dibagian ini:
      rm -rf ./dist/library/ mkdir ./dist/library, fungsinya untuk hapus directory yg sudah exists, simplenya: delete -> create -> delete -> create

      Setelah itu, karena sudah dapet list folder apa aja yang ada di folder components/, kita pake for loop, dan tinggal sesuain aja sama param nya.

      Note:

      • ng run: command dari angular cli untuk running
      • cat: untuk concat/gabungin semua file
      • cp: untuk copy file/folder, pake option -r biar bisa copy file sm folder
      • rm: untuk delete file/folder
      posted in Front End
    • React Hooks: useContext()

      Use Context

      Berbicara tentang context, simpelnya context ini adalah global state manajemen bawaan React. Dengan menggunakan context, kita bisa mempasing data/mengirim data dari parent komponen ke child komponen tanpa harus menggunakan props untuk melewati level2nya.

      Di dokumentasi React sendiri sempat disinggung mengenai component tree, ini menjadi maksud bahwa cara berfikir React, adalah struktur hierarki, yang artinya komponen terbagi2 menjadi susunan kecil piece by piece, sub by sub atau level by level. Perumpamaannya seperti ini, ada komponen orang tua dan ada komponen anak-anak:

      • FilterableProductTable
        • SearchBar
        • ProductTable
          • ProductCategoryRow
          • ProductRow

      React menggunakan konsep props dan state untuk berinteraksi antara komponen dengan proses inputan dan data. Konsep yang cerdas menurut saya, tapi masalahnya adalah ada beberapa pertanyaan 'apakah state ini berlaku di semua komponen? Atau hanya di komponen itu sendiri saja?, Ketika komponen saya nantinya sudah banyak cabang2, banyak melalui level sampai 5 level, apa saya harus menggunakan props untuk sharing input terus menerus?'

      Jika kita membaca dokumentasi, React memberikan beberapa solusi tepat dari masalah diatas. 'If you only want to avoid passing some props through many levels, component composition is often a simpler solution than context.' artinya kalau cuman untuk menghindari melewatkan beberapa props melalui banyak level, kita bisa menggunakan komposisi komponen ini cara yang lebih mudah daripada menggunakan context.

      Namun, bila tujuannya untuk sharing data antar komponen yang sifatnya global seperti: authentikasi user, tema, cache data, dan language, maka ini adalah cara yang tepat untuk menggunakan context. Inipun kita juga harus hati-hati dan tepat dalam menggunakannya 'apply it sparingly because it makes component reuse more difficult.'.

      Component Composition

      Ini sebenernya merupakan sebuah komponen pattern yang digunakan untuk membangun komponen dari komponen lain menjadi kesatuan yang lebih besar, istilahnya seperti gotong royong. Tetapi, konsep ini punya aturan, casenya seperti ini anggap saja dalam gotong royong terdapat 2 role, role sebagai ketua kelompok dan role sebagai anggota.

      Aturannya adalah ketika para anggota saling bahu membahu untuk membawa box(misal) maka anggota lain tidak perlu tahu isi box tersebut apa. Tugasnya anggota hanya membawa box tersebut sampai ke tujuan. Sedangkan ketua kelompok tugasnya mengawasi dan menyiapkan box supaya siap dikirim ke pelanggan, seperti *label, rincian, dll`.

      Jika di realitakan dalam bentuk kode, contohnya seperti dibawah ini:

      function Anggota(props){
        return <span>{ props.text }</span>
      }
       
      function Anggota_Dua(props){
        return <button>{ props.render }</button> // Cuman sebagai terusan untuk merender <Anggota/>
      }
       
      function KetuaKelompok(){
        const btnText = <Anggota text="Click Me" />;
        return <Anggota_Dua render={btnText}/>
      }
      
      <KetuaKelompok/>
      

      Pada intinya komposisi komponen ini tujuannya adalah sebagai terusan yang dipassing/dikirim melalui props. Mirip seperti konsep { props.children }, lebih jelasnya bisa lihat example. Cara ini lebih tepat dan mudah dibandingkan dengan context

      Context

      Seperti yang dijelaskan diatas, context adalah global state management. Sebenernya harusnya disini saya langsung saja menjelaskan bagaimana cara dan konsep useContext() hooks, cuman karena ada beberapa proses yang berhubungan jadi saya akan jelaskan secara detail.

      Pada beberapa source biasanya menggunakan useReducer() untuk melakukan manipulasi state, padahal case yang dialami hanya seperti dibawah ini:

      // Reducer
      export const Reducer = (state = initialState) => {
          ...
          case StepActionStatus.ADD_FORM_DATA_PREV: {
              return {
                  ...state,
                  storedFormData: [...state.storedFormData.concat(action.payload.allFields)].reverse().sort()
              }
          }
          ...
      }
      

      Pointnya tujuan dari kode itu adalah hanya untuk menggabungkan data di store dengan payload (context), tentunya cara ini malah menyulitkan, kalau ada cara yang lebih mudah kenapa cari yang sulit:). Maka dari itu, selagi casenya ga kompleks2 banget, pake useState() aja udah cukup (bahkan ini cara yang lebih tepat).

      Ini adalah cara best praktis yang umumnya sering kali digunakan, yaitu dengan menggunakan suatu fungsi untuk melakukan perubahan nilai pada context. Disini saya buat 2 versi, yaitu dengan menggunakan pure useState, dan dengan bantuan useCallback, Perhatikan kode dibawah ini:

      const initialState = {
          state: ''
      }
      
      export const Context = React.createContext<typeof initialState | any>(undefined);
      
      function ContextProvider(props: React.PropsWithChildren<{}>) {
          const [state, setState] = React.useState(initialState);
      
          return (
              <Context.Provider value={{ state, setState }}>
                  {props.children}
              </Context.Provider>
          )
      }
      
      export default ContextProvider;
      
      
      const contextState = React.useContext(Context);
      const { setState } = contextState;
      

      Pada kode diatas, value pada Context.Provider diambil dari local state, jadi ketika context ini di use maka value yg didapat adalah state & setState. Seperti yang dijelaskan pada module sebelumnya, [state, setState] variabel pertama untuk nilai, variabel kedua untuk merubah nilai.

      Untuk cara yang kedua, hampir mirip dengan cara yang pertama, cuman bedanya ditambah useCallback, perhatikan kode dibawah ini:

      const initialStateCallback = {
          callbackState: ''
      }
      
      export const ContextCallback = React.createContext<typeof initialStateCallback | any>(undefined);
      
      function ContextCallbackProvider(props: React.PropsWithChildren<{}>) {
          const [callbackState, setCallbackState] = React.useState(initialStateCallback);
      
          // With useCallback (prefered)
          const setContextCallback = React.useCallback(
              newState => {
                  return setCallbackState({
                      callbackState: { ...newState }
                  })
              },
              [callbackState, setCallbackState]
          );
      
          const getContextCallback = React.useCallback(
              () => ({ setContextCallback, ...callbackState }),
              [callbackState, setContextCallback]
          );
      
          return (
              <ContextCallback.Provider value={getContextCallback()}>
                  {props.children}
              </ContextCallback.Provider>
          )
      }
      
      export default ContextCallbackProvider;
      
      
      const contextCallbackState = React.useContext<any>(ContextCallback);
      const { setContextCallback } = contextCallbackState;
      

      Kamu juga bisa menginitialize useCallback() nya di komponennya langsung cuman saya lebih prefer di providernya sih. Contoh kodenya seperti ini:

      const handlerCallback = React.useCallback(() => {
          setState({
              state: 'Transform to useCallback()',
          })
      }, [contextState.state, setState]);
      
      <button onClick={handlerCallback}>Click Me</button>
      

      Alasannya mengapa menggunakan useCallback() adalah karena ini 'Using an arrow function in render creates a new function each time the component renders, which may break optimizations based on strict identity comparison.' artinya arrow function () => { ... } ini akan membuat fungsi baru setiap kali komponen dirender ulang, ini bisa menyebabkan memory leaks.

      Next Hooks

      Lihat versi full module penggunaan hooks secara lengkap dalam Bahasa Indonesia
      https://github.com/natserract/react-hooks-deepdive. Kamu juga bisa ikut berkontribusi, pull request are welcome πŸ˜‰

      posted in Front End
    • Functional Programming di Rust

      Functional Programming di Rust

      Sebulan lalu ketika pertama kali mendevelop sebuah non komersial project menggunakan ReasonML, saya mendapat sebuah pengalaman baru, yaitu functional programming. Bahasa ini merupakan alternative syntax dari OCaml. OCaml sendiri merupakan purely functional language, fitur-fitur yang ditawarkan menarik. Contohnya: type inference, strongly type system, algebraic datatypes, dan masih banyak lagi. Menarik bukan?

      Nah setelah mencoba language tersebut, saya mulai interest dengan namanya functional programming. Usut punya usut, akhirnya saya coba mengimplementasikan paradigma tersebut di bahasa berbeda yaitu Rust.

      Introduction

      Functional programming (FP) adalah paradigma pemrograman dimana memungkinkan kita untuk menulis kode program yang ekspresif, ringkas, dan elegan. Functional programming juga membantu developer untuk mengatur kodenya agar tidak DRY (Don't Repeat Yourself) alias tidak menulis kode yang sama berulang-ulang kali. Functional language lainnya contohnya seperti Lisp, Clojure, Erlang, Haskell, R, dan masih banyak lagi.

      Okay, but why Rust?

      Pertanyaannya, apakah Rust functional programming language? jawabannya, tidak. Walaupun Rust sendiri terinspirasi dari ML family of language, dia bukan functional. Tetapi beruntungnya Rust mempunyai beberapa fitur yang mirip dengan bahasa fungsional lainnya, seperti: algebraic datatypes, expressive types, dan lain-lain.

      Lists yang akan dibahas

      • Primitive Types
      • Closures
      • Currying
      • Recursion
      • Higher Order Functions(HOF)
      • Lazy evaluations

      Primitive Types

      Agar tidak langsung loncat lebih jauh, alangkah baiknya kita harus mengetahui beberapa tipe data yang ada di Rust. Ini juga berlaku untuk semua bahasa pemrogaman.

      Booleans

      Jenis tipe data yang paling sederhana adalah nilai true/false, di Rust ini disebut bool

      let x = true;
      let y: bool = false;
      

      Char

      Jenis tipe data char memiliki nilai single Unicode. Kita bisa menggunakan tipe data char dengan single tick (')

      let x = 'x';
      let two_hearts = 'πŸ’•';
      

      Tidak seperti beberapa bahasa lain, char di Rust nilainya bukan satu byte, tetapi empat.

      Numeric Types

      Rust mempunyai beberapa varian kategori tipe numeric, seperti signed(i) dan unsigned(u), fixed size (8, 16, 32, 64) dan variable(isize, usize) types.

      let x = 42; // `x` has type `i32`.
      let y = 1.0; // `y` has type `f64`.
      

      Arrays

      Seperti banyak bahasa pemrograman lain, Rust juga memiliki tipe data array. Secara default, array di Rust tidak dapat diubah. Kecuali kamu menginisializenya dengan mut

      let a = [1, 2, 3]; // a: [i32; 3]
      let mut m = [1, 2, 3]; // m: [i32; 3]
      

      Functions

      Function juga memiliki tipe data! Contohnya seperti ini:

      fn foo(x: i32) -> i32 { x }
      let x: fn(i32) -> i32 = foo;
      

      Dalam case ini, fungsi foo() memiliki return type numeric: i32, dan mengembalikan nilai x.

      Untuk selengkapnya kamu bisa cek disini: primitive types

      Closures

      "Closure is a mechanism by which an inner function will have access to the variables defined in its outer function’s lexical scope even after the outer function has returned."

      Sampai disini paham? singkatnya closures adalah sebuah inner function yang mempunyai akses untuk mengambil suatu nilai diseluruh scopenya baik diluar maupun didalam.

      fn fmt(prev_str: &str) -> String {
          let mut new_str = String::new();
          
          let closure_annotated = |next_str| -> String {
              new_str.push_str(prev_str);
              new_str.push_str(next_str);
              return new_str;
          };
          
          closure_annotated("dolor sit amet")
      }
      
      let r_txt = "Lorem ipsum ";
      assert_eq!("Lorem ipsum dolor sit amet", fmt(r_txt));
      

      Dicase ini, dibagian new_str.push_str() dimana closure_annotated mengakses variable new_str lalu merubah nilai dalam variabel tersebut dan mereturn nya diluar scope.

      Currying

      Currying adalah teknik functional programming di mana kita dapat mengubah suatu fungsi dengan beberapa argumen menjadi urutan fungsi bersarang. Ini mengembalikan fungsi baru yang mengharapkan argumen inline berikutnya.

      #[derive(Debug)]
      struct States<'a> {
          a: &'a i32,
          b: &'a i32
      }
      
      trait Currying {
          type ReturnType: Fn(i32) -> i32;
          fn add(self) -> Self::ReturnType;
      }
      
      impl Currying for States<'static>{
          type ReturnType = Box<dyn Fn(i32) -> i32>;
         
          fn add(self) -> Self::ReturnType {
              Box::new(move|x| {
                  x * self.a
              })
          }
      }
      
      let r_value: States = States {
          a: &100,
          b: &100
      };
      
      let r1 = r_value.add();
      let r2 = r1(5);
      
      assert_eq!(500, r2);
      
      

      Terdapat 2 parameter disini, yaitu a, b dimana masing-masing mempunyai tipe data numeric, lalu dibagian trait adalah sebuah function interfaces, tempat untuk inisialisasi function. Traits ini mirip seperti typescript interfaces.

      Recursion

      Sederhananya recursion adalah suatu procedure/function yang memanggil dirinya sendiri, dimana fungsinya untuk membuat/mengolah data yang akan ingin ditampilkan.

      #[allow(non_camel_case_types)] 
      type i64_t = i64;
      
      trait Factor {
          fn factorial_tail_rec(val: i64_t) -> Self;
          fn factorial(num: i64_t) -> Self;
      }
      
      impl Factor for i64_t {
          fn factorial_tail_rec(val: i64_t) -> Self {
              val
          }
      
          fn factorial(num: i64_t) -> Self {
              match num {
                  0 => 1,
                  _ => num * Self::factorial_tail_rec(num - 1)
              }
          }
      }
      
      let result: i64_t = Factor::factorial(3); 
      assert_eq!(6, result);
      

      Ini adalah sebuah fungsi faktorial, dimana jika nilai argumen dari parameter num !== 0, maka nilai tersebut akan dikalikan dengan setiap angka dibawahnya. Misalnya (5! = 5 * 4 * 3 * 2 * 1 = 120).

      Higher Order Functions(HOF)

      Higher order function adalah fungsi yang menggunakan fungsi lain sebagai parameter atau sebagai hasil return.

      fn map<F>(arr: &[i32], func: F) -> Vec<i32> where F: Fn(&i32) -> i32{
          let mut new_array: Vec<i32> = vec![];
          for i in arr.iter() {
              new_array.push(func(i))
          }
          
          return new_array
      }
      
      let lists = vec![1, 4, 9, 16];
      let result = map(&lists, |i| *i + 2);
      
      assert_eq!(vec![3, 6, 11, 18], result)
      

      Jadi func dan map merupakan higher order function, dimana fungsi ini digunakan untuk mengubah setiap isi dari suatu array. Hasil returnnya adalah array baru dengan length yang sama dengan originalArray yang diubah.

      Lazy Evaluation

      Lazy evaluation atau non-strict evaluation adalah sebuah proses menahan evaluasi dari sebuah expression/function hingga nilainya diperlukan. Tujuannya agar menghindari evaluasi berulang.

      struct State {
          x: i32,
      }
      
      trait Lazy {
          fn add(&self) -> i32;
          fn multiply(&self) -> i32;
          fn add_or_multiply(&self, add: bool) -> i32;
      }
      
      impl Lazy for State {
          fn add(&self) -> i32 {
              println!("executing add");
              &self.x + &self.x
          }
      
          fn multiply(&self) -> i32 {
              println!("executing multiply");
              &self.x * &self.x
          }
      
          fn add_or_multiply(&self, add: bool) -> i32 { 
              match add {
                  true => self.add(),
                  false =>  self.multiply(),
              }
          }
      }
      
      let val: State = State {
          x: 20
      };
      
      assert_eq!(40, val.add_or_multiply(true));
      assert_eq!(400, val.add_or_multiply(false));
      

      Referensi

      • Functional Programming in Go
      • Eloquent Javascript Functional Programming
      • Closures Developer Mozilla

      Motivation

      Functional Programming (FP) memiliki banyak keuntungan, dan popularitasnya terus meningkat. Namun, setiap paradigma pemrograman dilengkapi fitur dan keunikan tersendiri dan FP tidak terkecuali. Semoga dengan adanya tulisan ini, dapat memberikan manfaat bagi pembacanya. Sekian dari saya terimakasih ✌️

      Repository: rustfp.github.rs

      posted in Back End
    • Angular - DOM Manipulation | You Don't Need Jquery

      Bagi pengguna Angular, mungkin sudah pernah menggunakan ataupun pernah dengar apa itu Renderer. Fitur ini sudah muncul sejak Angular versi 4. Bagi kamu pengguna Angular 8/9, saatnya bermigrasi ke Renderer2. Alasannya bisa kalian baca disini: Renderer to Renderer2 migration

      Sebelum lebih jauh, kita harus fahami dlu apa itu DOM, DOM atau Document Object Model, adalah dokumen (HTML) yang dimodelkan dalam sebuah objek, simplenya DOM adalah keseluruhan dokumen html yang dibentuk saat web diload oleh browser pertama kali. Jadi dengan DOM HTML ini kita dapat melakukan berbagi manipulasi pada element HTML, seperti: get, add, change, add atau delete.

      WAW

      Jika kamu pengguna Angular yg sebelumnya terbiasa dengan Jquery, maka tidak menutup kemungkinan kamu akan memilih Jquery sebagai pilihan pertama jika ketemu case seperti ini (bisa jadi) πŸ˜…, karena.. ya tentunya krn jquery sudah memanjakan penggunanya lewat API2nya dia. So, ini tidak recommended ya, kalo mau tau alasannya bisa baca disini: STOP TRYING TO USE JQUERY IN ANGULAR

      Okey, di case kali ini kita akan langsung bermain dengan Renderer2.

      Membuat element

      Jika di jquery untuk membuat element kamu bisa melakukannya seperti ini: $("<div/>").appendTo("div#main"); cukup mudah bukan? πŸ˜…. Nah, mulai sekarang klo bisa kurang-kurangin / tinggalkan cara pandang jquery ini ya, krn di Angular caranya cukup berbeda.

      Code:

          export class CreateElComponent implements OnInit {
              constructor(
                  private renderer: Renderer2,
                  private hostElement: ElementRef,
              ) {}
      
              ngOnInit() {
                  const createLabelEl = this.renderer.createElement('label');
                  const createInputEl = this.renderer.createElement('input');
      
                  this.renderer.setStyle(createLabelEl, 'display', 'block');
                  this.renderer.setAttribute(createInputEl, 'type', 'text');
                  
                  this.renderer.appendChild(createLabelEl, createInputEl);
                  this.renderer.appendChild(this.hostElement.nativeElement, createLabelEl);
              }
          }
      

      Pada code diatas, proses pembuatan element dilakukan di ngOnInit() jdi ketika Angular sudah selesai membuat component. Kemudian terdapat beberapa function disana contohnya createElement() yg fungsinya utk membuat element, lalu setStyle() dan setAttribute() untuk menambahkan style dan attribute di element tersebut, selengkapnya kamu bisa baca disini: Renderer2 Doc. Setelah komponen dibuat, maka komponen di append dengan komponen rootnya.

      Jadi simplenya, Renderer2 ini tugasnya merender/menampilkan element yang sudah dibuat, kemudian ElementRef tugasnya sebagai component reference dari Renderer2, contohnya: membuat element, select element, etc.

      Custom Directive - Add/Remove Class

      Seperti yang dijelaskan sebelumnya, kamu bisa menggunakan Renderer2 ini di custom directive

      @Directive({
          selector: `custom-directive, [customDirective]`,
          host: {
              'class': `custom-directive`
          }
      })
      export class CustomDirective {
          constructor(
              private renderer: Renderer2, 
              private hostElement: ElementRef
          ) {}
      
          isClicked = false;
      
          @HostListener('click', ['$event.target'])
          _onClick() {
              this.isClicked = !this.isClicked;
      
              switch (this.isClicked ) {
                  case true: {
                      this.renderer.addClass(this.hostElement.nativeElement.parentNode, 'isActive');
                      break;
                  }
                  case false: {
                      this.renderer.removeClass(this.hostElement.nativeElement.parentNode, 'isActive');
                      break;
                  }
              }
          }
      }
      

      Pada directive custom-directive ini, ketika terdapat event click, maka akan mentoggle sebuah class isActive, kamu bisa menggunakan fungsi @HostListener() untuk menghandle events yang ada pada element directive ini.

      Selecting elements

      Kadang kala kamu ingin memilih suatu element, misalnya by id, class, ataupun tagname. Kamu juga masih bisa menggunakan API2 yg ada seperti di vanilla js (not jquery)

      export class SelectingElComponent implements OnInit, AfterViewInit {
          constructor(
              private renderer: Renderer2, 
              private hostElement: ElementRef
          ) {}
      
          ngAfterViewInit(){
              const findInputEl = this.hostElement.nativeElement.querySelector('input[type="checkbox"]');
              const findAllBtnEl = this.hostElement.nativeElement.querySelectorAll('button');
              const hasClass = this.hostElement.nativeElement.classList.contains('container');
      
              console.group(
                  findInputEl,
                  findAllBtnEl,
                  hasClass
              );
          }
      
          ngOnInit(){
              setTimeout(() => {
                  // For alternative
              }, 1)
          }
      }
      

      Catatan disini, jdi selain menggunakan ngAfterViewInit() lifecycle, kamu juga bisa menggunakan setTimeout() sbg alternative untuk mendetect suatu element, karena kadang kala terdapat beberapa case dimana kita ingin mendetect suatu element selain di ngAfterViewInit() contohnya di constructor, jika tanpa setTimeout(), tentunya outputnya akan undefined, karena fungsi dipanggil sebelum component/directive dirender.

      Thanks.

      posted in Front End
    • Javascript ORM?

      @Joe-Prabawa btw saya belum pernah make ORM di js, but just for sharing:
      TypeORM: https://github.com/typeorm/typeorm
      Sequelize: https://github.com/sequelize/sequelize

      posted in Back End
    • Ayo kenalin dirimu!

      Hey! Salam kenal semua. Perkenalkan nama saya Alfin, saat ini bekerja di Fantasktic. Fokus di frontend development, untuk sekarang lagi mendalami ReasonML & Rust. Habit saya, suka makan yg pedes2, sekian dan mohon bantuannya, teman2 semua terimakasih.

      posted in Diskusi Umum
    • Ngoding React di Vue (include: TypeScript) πŸ”₯

      @Joe-Prabawa Wah iya bener https://github.com/vuejs/composition-api/pull/230, keren nih udah make vue composition api, lanjutkan πŸ‘

      posted in Front End
    • Share color-theme/skin text editor mu disini!

      Screen Shot 2020-03-31 at 22.49.31.png

      Text editor: MacVim
      ColorScheme: Gruvbox - Dark
      Font: FiraCode

      (baru2 make vim) πŸ˜‚

      posted in Diskusi Umum

    Latest posts made by natserract

    • Ayo kenalin dirimu!

      @Andika-Wira halo andika, welcome! 😊

      posted in Diskusi Umum
    • React Hooks: useContext()

      Use Context

      Berbicara tentang context, simpelnya context ini adalah global state manajemen bawaan React. Dengan menggunakan context, kita bisa mempasing data/mengirim data dari parent komponen ke child komponen tanpa harus menggunakan props untuk melewati level2nya.

      Di dokumentasi React sendiri sempat disinggung mengenai component tree, ini menjadi maksud bahwa cara berfikir React, adalah struktur hierarki, yang artinya komponen terbagi2 menjadi susunan kecil piece by piece, sub by sub atau level by level. Perumpamaannya seperti ini, ada komponen orang tua dan ada komponen anak-anak:

      • FilterableProductTable
        • SearchBar
        • ProductTable
          • ProductCategoryRow
          • ProductRow

      React menggunakan konsep props dan state untuk berinteraksi antara komponen dengan proses inputan dan data. Konsep yang cerdas menurut saya, tapi masalahnya adalah ada beberapa pertanyaan 'apakah state ini berlaku di semua komponen? Atau hanya di komponen itu sendiri saja?, Ketika komponen saya nantinya sudah banyak cabang2, banyak melalui level sampai 5 level, apa saya harus menggunakan props untuk sharing input terus menerus?'

      Jika kita membaca dokumentasi, React memberikan beberapa solusi tepat dari masalah diatas. 'If you only want to avoid passing some props through many levels, component composition is often a simpler solution than context.' artinya kalau cuman untuk menghindari melewatkan beberapa props melalui banyak level, kita bisa menggunakan komposisi komponen ini cara yang lebih mudah daripada menggunakan context.

      Namun, bila tujuannya untuk sharing data antar komponen yang sifatnya global seperti: authentikasi user, tema, cache data, dan language, maka ini adalah cara yang tepat untuk menggunakan context. Inipun kita juga harus hati-hati dan tepat dalam menggunakannya 'apply it sparingly because it makes component reuse more difficult.'.

      Component Composition

      Ini sebenernya merupakan sebuah komponen pattern yang digunakan untuk membangun komponen dari komponen lain menjadi kesatuan yang lebih besar, istilahnya seperti gotong royong. Tetapi, konsep ini punya aturan, casenya seperti ini anggap saja dalam gotong royong terdapat 2 role, role sebagai ketua kelompok dan role sebagai anggota.

      Aturannya adalah ketika para anggota saling bahu membahu untuk membawa box(misal) maka anggota lain tidak perlu tahu isi box tersebut apa. Tugasnya anggota hanya membawa box tersebut sampai ke tujuan. Sedangkan ketua kelompok tugasnya mengawasi dan menyiapkan box supaya siap dikirim ke pelanggan, seperti *label, rincian, dll`.

      Jika di realitakan dalam bentuk kode, contohnya seperti dibawah ini:

      function Anggota(props){
        return <span>{ props.text }</span>
      }
       
      function Anggota_Dua(props){
        return <button>{ props.render }</button> // Cuman sebagai terusan untuk merender <Anggota/>
      }
       
      function KetuaKelompok(){
        const btnText = <Anggota text="Click Me" />;
        return <Anggota_Dua render={btnText}/>
      }
      
      <KetuaKelompok/>
      

      Pada intinya komposisi komponen ini tujuannya adalah sebagai terusan yang dipassing/dikirim melalui props. Mirip seperti konsep { props.children }, lebih jelasnya bisa lihat example. Cara ini lebih tepat dan mudah dibandingkan dengan context

      Context

      Seperti yang dijelaskan diatas, context adalah global state management. Sebenernya harusnya disini saya langsung saja menjelaskan bagaimana cara dan konsep useContext() hooks, cuman karena ada beberapa proses yang berhubungan jadi saya akan jelaskan secara detail.

      Pada beberapa source biasanya menggunakan useReducer() untuk melakukan manipulasi state, padahal case yang dialami hanya seperti dibawah ini:

      // Reducer
      export const Reducer = (state = initialState) => {
          ...
          case StepActionStatus.ADD_FORM_DATA_PREV: {
              return {
                  ...state,
                  storedFormData: [...state.storedFormData.concat(action.payload.allFields)].reverse().sort()
              }
          }
          ...
      }
      

      Pointnya tujuan dari kode itu adalah hanya untuk menggabungkan data di store dengan payload (context), tentunya cara ini malah menyulitkan, kalau ada cara yang lebih mudah kenapa cari yang sulit:). Maka dari itu, selagi casenya ga kompleks2 banget, pake useState() aja udah cukup (bahkan ini cara yang lebih tepat).

      Ini adalah cara best praktis yang umumnya sering kali digunakan, yaitu dengan menggunakan suatu fungsi untuk melakukan perubahan nilai pada context. Disini saya buat 2 versi, yaitu dengan menggunakan pure useState, dan dengan bantuan useCallback, Perhatikan kode dibawah ini:

      const initialState = {
          state: ''
      }
      
      export const Context = React.createContext<typeof initialState | any>(undefined);
      
      function ContextProvider(props: React.PropsWithChildren<{}>) {
          const [state, setState] = React.useState(initialState);
      
          return (
              <Context.Provider value={{ state, setState }}>
                  {props.children}
              </Context.Provider>
          )
      }
      
      export default ContextProvider;
      
      
      const contextState = React.useContext(Context);
      const { setState } = contextState;
      

      Pada kode diatas, value pada Context.Provider diambil dari local state, jadi ketika context ini di use maka value yg didapat adalah state & setState. Seperti yang dijelaskan pada module sebelumnya, [state, setState] variabel pertama untuk nilai, variabel kedua untuk merubah nilai.

      Untuk cara yang kedua, hampir mirip dengan cara yang pertama, cuman bedanya ditambah useCallback, perhatikan kode dibawah ini:

      const initialStateCallback = {
          callbackState: ''
      }
      
      export const ContextCallback = React.createContext<typeof initialStateCallback | any>(undefined);
      
      function ContextCallbackProvider(props: React.PropsWithChildren<{}>) {
          const [callbackState, setCallbackState] = React.useState(initialStateCallback);
      
          // With useCallback (prefered)
          const setContextCallback = React.useCallback(
              newState => {
                  return setCallbackState({
                      callbackState: { ...newState }
                  })
              },
              [callbackState, setCallbackState]
          );
      
          const getContextCallback = React.useCallback(
              () => ({ setContextCallback, ...callbackState }),
              [callbackState, setContextCallback]
          );
      
          return (
              <ContextCallback.Provider value={getContextCallback()}>
                  {props.children}
              </ContextCallback.Provider>
          )
      }
      
      export default ContextCallbackProvider;
      
      
      const contextCallbackState = React.useContext<any>(ContextCallback);
      const { setContextCallback } = contextCallbackState;
      

      Kamu juga bisa menginitialize useCallback() nya di komponennya langsung cuman saya lebih prefer di providernya sih. Contoh kodenya seperti ini:

      const handlerCallback = React.useCallback(() => {
          setState({
              state: 'Transform to useCallback()',
          })
      }, [contextState.state, setState]);
      
      <button onClick={handlerCallback}>Click Me</button>
      

      Alasannya mengapa menggunakan useCallback() adalah karena ini 'Using an arrow function in render creates a new function each time the component renders, which may break optimizations based on strict identity comparison.' artinya arrow function () => { ... } ini akan membuat fungsi baru setiap kali komponen dirender ulang, ini bisa menyebabkan memory leaks.

      Next Hooks

      Lihat versi full module penggunaan hooks secara lengkap dalam Bahasa Indonesia
      https://github.com/natserract/react-hooks-deepdive. Kamu juga bisa ikut berkontribusi, pull request are welcome πŸ˜‰

      posted in Front End
    • Buat Utility JavaScript Kamu Lebih Scal/Read(able)

      @wayanjimmy yoi kak, aku pake plugin ini kalo di vscode biar bisa generate jsdoc otomatis πŸ˜€ https://marketplace.visualstudio.com/items?itemName=stevencl.addDocComments

      posted in Front End
    • Buat Utility JavaScript Kamu Lebih Scal/Read(able)

      Bagi para developer, kata utility tentunya sudah tak asing di dengar, hampir di setiap project, utility ini akan selalu dibuat. Utility biasanya isinya adalah functions2, atau service, yang sifatnya reusable atau istilahnya 'write once, use many times'.

      Di tulisan kali ini kita tidak akan membuat utility, tpi lebih ke bagaimana mengembangkan utility yang kamu buat supaya lebih readable, dan bisa mudah digunakan oleh developer lain nantinya.

      Tapi sebelum itu, ada beberapa pertanyaan, apa bener javascript itu dynamic typing?, coba perhatikan kode dibawah ini:

      index.js
      Screen Shot 2020-12-22 at 23.25.51.png
      Dalam kode diatas, type tidak didefinisikan, tapi Javascript sudah secara otomatis mendeteksi type ketika value dibuat. Perhatikan lagi, ketika cursor di hover
      Screen Shot 2020-12-22 at 23.26.00.png
      Dari sini kita tahu, bahwa Javascript itu Dynamic Typing

      Sebelum ke maincase, bisa baca source ini dlu:

      • Difference arguments and parameters
      • JavaScript is Dynamic Typing

      Main case

      Ketika membuat sebuah function, pastinya ada nama function, parameter(optional), dan return dari function tersebut, example:

      index.js
      Screen Shot 2020-12-23 at 09.36.59.png
      Mungkin kalian sudah tau, maksud dari cara kerja function ini, ekspetasinya adalah return dari function ini harus mengembalikan nilai true, yang isi parameter typenya mempunyai masing-masing tipe data nya adalah string.

      Tapi problemnya, ketika function ini digunakan, apakah argumen yang dimasukkan di function isShouldBeString() selalu bertipe data string? bisa jadi tidak!.
      Mengapa? karena type dari kedua parameter tersebut tidak di define/definisikan.

      Jika menggunakan TypeScript, tentu masalah ini akan selesai sepersekian detik. Tpi bagaimana pengguna JavaScript menyelesaikan ini? "Ya definisiin typenya masbro!"

      Jawabannya 70% hampir betul, definiisin typenya. Tapi tidak dengan type definitions, melainkan JSDoc. Bisa dibantu juga dengan JSDoc eslint plugin, tapi kali ini kita tidak menggunakan eslint.

      What? Apa itu jsdoc?, singkatnya JSDoc itu adalah dokumentasi dari source code yang kita buat, bentuknya simple hanya berupa komen tpi penggunaannya sangat berguna nantinya. Contohnya ada pada kode dibawah ini:
      Screen Shot 2020-12-23 at 17.19.11.png

      Perhatikan pada line 23 - 27, ada 3 tag, pada tag@param, fungsinya untuk membuat dokumentasi dari tipe data dari parameter function isShouldBeString(), kemudian tag @returns artinya apa returnnya, sedangkan tag @example adalah contoh penggunaan dari function tersebut. Selain 3 tag itu, kalian juga bisa menggunakan tag2 lain

      Jika kita hover functionnya, maka hasilnya akan seperti ini
      Screen Shot 2020-12-23 at 17.19.21.png

      Sangat mudah bukan?, disini sangat jelas terlihat bahwa function isShouldBeString() itu maksudnya untuk apa sih, cara penggunaan function ini yang tepat bagaimana, dll. Tentunya ini bisa membantu developer lain untuk bisa mudah mengerti utility yang kita buat.

      So programming it's all about solving problem right? Maka dari itu, bisa mulai dari sekarang untuk disiplin dalam meng-kode. Thanks!

      posted in Front End
    • Ayo kenalin dirimu!

      @Adiatma-Kamarudin halo mas πŸ‘ πŸ‘

      posted in Diskusi Umum
    • Ayo kenalin dirimu!

      @Doni-Wirawan mantap broh πŸ‘ πŸ‘

      posted in Diskusi Umum
    • Angular - DOM Manipulation | You Don't Need Jquery

      Bagi pengguna Angular, mungkin sudah pernah menggunakan ataupun pernah dengar apa itu Renderer. Fitur ini sudah muncul sejak Angular versi 4. Bagi kamu pengguna Angular 8/9, saatnya bermigrasi ke Renderer2. Alasannya bisa kalian baca disini: Renderer to Renderer2 migration

      Sebelum lebih jauh, kita harus fahami dlu apa itu DOM, DOM atau Document Object Model, adalah dokumen (HTML) yang dimodelkan dalam sebuah objek, simplenya DOM adalah keseluruhan dokumen html yang dibentuk saat web diload oleh browser pertama kali. Jadi dengan DOM HTML ini kita dapat melakukan berbagi manipulasi pada element HTML, seperti: get, add, change, add atau delete.

      WAW

      Jika kamu pengguna Angular yg sebelumnya terbiasa dengan Jquery, maka tidak menutup kemungkinan kamu akan memilih Jquery sebagai pilihan pertama jika ketemu case seperti ini (bisa jadi) πŸ˜…, karena.. ya tentunya krn jquery sudah memanjakan penggunanya lewat API2nya dia. So, ini tidak recommended ya, kalo mau tau alasannya bisa baca disini: STOP TRYING TO USE JQUERY IN ANGULAR

      Okey, di case kali ini kita akan langsung bermain dengan Renderer2.

      Membuat element

      Jika di jquery untuk membuat element kamu bisa melakukannya seperti ini: $("<div/>").appendTo("div#main"); cukup mudah bukan? πŸ˜…. Nah, mulai sekarang klo bisa kurang-kurangin / tinggalkan cara pandang jquery ini ya, krn di Angular caranya cukup berbeda.

      Code:

          export class CreateElComponent implements OnInit {
              constructor(
                  private renderer: Renderer2,
                  private hostElement: ElementRef,
              ) {}
      
              ngOnInit() {
                  const createLabelEl = this.renderer.createElement('label');
                  const createInputEl = this.renderer.createElement('input');
      
                  this.renderer.setStyle(createLabelEl, 'display', 'block');
                  this.renderer.setAttribute(createInputEl, 'type', 'text');
                  
                  this.renderer.appendChild(createLabelEl, createInputEl);
                  this.renderer.appendChild(this.hostElement.nativeElement, createLabelEl);
              }
          }
      

      Pada code diatas, proses pembuatan element dilakukan di ngOnInit() jdi ketika Angular sudah selesai membuat component. Kemudian terdapat beberapa function disana contohnya createElement() yg fungsinya utk membuat element, lalu setStyle() dan setAttribute() untuk menambahkan style dan attribute di element tersebut, selengkapnya kamu bisa baca disini: Renderer2 Doc. Setelah komponen dibuat, maka komponen di append dengan komponen rootnya.

      Jadi simplenya, Renderer2 ini tugasnya merender/menampilkan element yang sudah dibuat, kemudian ElementRef tugasnya sebagai component reference dari Renderer2, contohnya: membuat element, select element, etc.

      Custom Directive - Add/Remove Class

      Seperti yang dijelaskan sebelumnya, kamu bisa menggunakan Renderer2 ini di custom directive

      @Directive({
          selector: `custom-directive, [customDirective]`,
          host: {
              'class': `custom-directive`
          }
      })
      export class CustomDirective {
          constructor(
              private renderer: Renderer2, 
              private hostElement: ElementRef
          ) {}
      
          isClicked = false;
      
          @HostListener('click', ['$event.target'])
          _onClick() {
              this.isClicked = !this.isClicked;
      
              switch (this.isClicked ) {
                  case true: {
                      this.renderer.addClass(this.hostElement.nativeElement.parentNode, 'isActive');
                      break;
                  }
                  case false: {
                      this.renderer.removeClass(this.hostElement.nativeElement.parentNode, 'isActive');
                      break;
                  }
              }
          }
      }
      

      Pada directive custom-directive ini, ketika terdapat event click, maka akan mentoggle sebuah class isActive, kamu bisa menggunakan fungsi @HostListener() untuk menghandle events yang ada pada element directive ini.

      Selecting elements

      Kadang kala kamu ingin memilih suatu element, misalnya by id, class, ataupun tagname. Kamu juga masih bisa menggunakan API2 yg ada seperti di vanilla js (not jquery)

      export class SelectingElComponent implements OnInit, AfterViewInit {
          constructor(
              private renderer: Renderer2, 
              private hostElement: ElementRef
          ) {}
      
          ngAfterViewInit(){
              const findInputEl = this.hostElement.nativeElement.querySelector('input[type="checkbox"]');
              const findAllBtnEl = this.hostElement.nativeElement.querySelectorAll('button');
              const hasClass = this.hostElement.nativeElement.classList.contains('container');
      
              console.group(
                  findInputEl,
                  findAllBtnEl,
                  hasClass
              );
          }
      
          ngOnInit(){
              setTimeout(() => {
                  // For alternative
              }, 1)
          }
      }
      

      Catatan disini, jdi selain menggunakan ngAfterViewInit() lifecycle, kamu juga bisa menggunakan setTimeout() sbg alternative untuk mendetect suatu element, karena kadang kala terdapat beberapa case dimana kita ingin mendetect suatu element selain di ngAfterViewInit() contohnya di constructor, jika tanpa setTimeout(), tentunya outputnya akan undefined, karena fungsi dipanggil sebelum component/directive dirender.

      Thanks.

      posted in Front End
    • BaliJS Quiz #3

      Pengumuman Pemenang

      Halo gaes, setelah melewati proses yang berat untuk menentukan siapa aja pemenangnya berdasarkan:

      ketepatan algoritma
      kecepatan komputasi
      tercepat menjawab
      penjelasan time complexity (optional utk siswa/mahasiswa)


      Maka, kami sudah tentukan pemenang dari BaliJS Quiz #3 adalah:

      @refojunior
      @Wahyu-Fadzar

      Selamat untuk pemenang, dan terimakasih banget untuk yang berpartisipasi. Untuk yang belum menang, jangan berkecil hati. Masih ada kesempatan di bulan berikutnya!

      Hadiah OVO/Gopay akan dikirimkan setelah pengumuman ini.


      Akhir Kata

      Bagi yang mau diskusi bagaimana solusinya, atau sharing apa aja yg teman-teman baru pelajari melalui kuis ini, silakan teman-teman balas topic ini ya.

      Sampai jumpa di BaliJS Quis #4

      posted in Quiz
    • Ayo kenalin dirimu!

      @Wayan-Mastra Hallo kak salam kenal 😊

      posted in Diskusi Umum
    • Ayo kenalin dirimu!

      @Indraawagin Mantap πŸ‘

      posted in Diskusi Umum