Javscript

2020’de Bileşenleri Manipüle Etmenin ve Bileşenlerle Çalışmanın 9 Yolu – JSManifest

Özellikle JavaScript topluluğunda yenilikler hızla patlamaya devam ederken, bir web geliştiricisi olmak için harika bir zaman! Tepki karmaşık kullanıcı arabirimleri oluşturmak için inanılmaz bir kitaplıktır ve React’te yeniyseniz, bu makale web geliştiricilerinin bunları emrinizde kullanmanın ne kadar güçlü olduğunu anlamanıza yardımcı olabilir. Ve tepki vermek için yeni değilseniz, o zaman muhtemelen bu yazıda yeni bir şey bulamayacaksın ancak inşallah Tepki bileşenleriyle çalışmak için hem eski hem de yeni stratejileri ortaya çıkarmaya çalışırken bu yazıda yeni bir şey olabilir.

Bu yazıda, 2020’de React bileşenlerini manipüle etmenin ve bunlarla çalışmanın 9 yolunu inceleyeceğiz.

Lafı fazla uzatmadan başlayalım!

1. Bileşen desteği

Mevcut bileşenlerin mantığını yeniden kullanmasını ve başka bir yere iletmesini sağlamanın birçok yolundan biri, mantığı şu şekilde özel bir bileşene geçirmenin bir yolunu sağlamaktır. sahne.

Gibi popüler tepki bileşen kitaplıkları Malzeme-UI bu stratejiyi kullan çok sık sağladıkları hemen hemen her bileşende.

Bunun mantığı yeniden kullanmanın iyi bir yolu olmasının iyi nedenleri var.

Örnek istersen şuna bak Özel Rota bileşenden bir Gatsby uygulama. Kimlik doğrulama mantığını kapsayan basit bir bileşendir. Geçerli kullanıcının kimliği doğrulanmadıysa, onları oturum açma ekranına yönlendirecektir. Aksi takdirde, devam edecek alınan bir bileşeni işlemek props.component. Geçtiği herhangi bir şeyi oluşturduğundan props.component, bu kimlik doğrulama mantığını istediğiniz kadar bileşen için yeniden kullanmaya açık bırakır. Yönlendirme mantığıyla çalışmayı basit ama güçlü bir yaklaşım haline getirir.

Not: Ayrıca, aşağıdaki gibi bir HTML DOM öğesini temsil eden bir dize iletebilirsiniz: "div" veya "span" ve yine de bir bileşen olarak işlenecek, çünkü tepki dahili olarak React.createElement’i çağırır eleman olarak geçmek type.

2. Bir çağrıda öğeleri, sınıf bileşenlerini veya işlev bileşenlerini oluşturma

React geliştirici ekibi, kullanıcı arayüzünüzün nasıl görünmesi gerektiğini tanımlarken JSX kullanmanızı önerir.

Ancak JSX kullanmanın nihayetinde yalnızca arama yapmak için sözdizimsel şeker olduğunu unutmayın. React.createElement. Bu nedenle güvenle kullanabileceğinizi belirtmekte fayda var. React.createElement bileşenlerinizi de oluşturmak için!

kullanmanın bazı faydaları vardır React.createElement JSX üzerinden.

Beni en çok ilgilendiren bu avantajlardan biri, kullanmaya başladığımızdan beri beni normal JavaScript yazmaya geri döndürmesi. sadece işlevler. Diğer faydalar, bu çağrıyı işlemekten kaçınmayı ve tüm uygulama ayrıntılarına tek bir kod bloğunda erişmeyi içerir, böylece JavaScript’in gerçekleştirmesi gereken fazladan adımdan kaçınırız.

Tepki-final-formunun arkasındaki ekip bu kalıbı kapsamlı bir şekilde kullanır kendi saha bileşenlerini oluşturmak için bir fabrika olarak.

3. Yüksek Dereceli Bileşenler (HOC) ile sahne donanımlarını ele geçirin

Daha yüksek dereceli bileşenler, React’te bileşen mantığını yeniden kullanmak için gelişmiş bir teknik olarak eski günlerde adil bir şöhret payına sahipti. Ancak hala öyle. Temel olarak, bir tepki bileşenini argüman olarak alan ve tamamen geri döndüren işlevlerdir. yeni bileşen.

Bu yaklaşımı kullanmak, bir bileşenin bir içindeki donanımların üzerine yazmanıza ve kaçırmanıza izin verir. “görünmez” Orta tabaka. Bu “orta katman”, üst düzey bileşenin mantığının gerçekleştiği yerdir. Sarılmış bileşenin donanımlarının üzerine yazmayı veya işleme davranışlarını kontrol etmeyi seçebilirler.

Bunu göstermek için bir barebone yazdım. withAuthValidation daha yüksek dereceli bileşen bu bir girdi iletilecek (DeactivatorInput) yalnızca yönetici kullanıcılara sunulacaktır. İlk önce bir bileşeni destek olarak alır, bazı kimlik doğrulama mantığı gerçekleştirir ve kullanıcının kimliği doğrulanmadıysa, o zaman bunu deneyecektir. devre dışı bırakmak girdi:

import React from 'react'

function isAuthed(token) {
  
}

const withAuthValidation = (WrappedComponent) => {
  return (props) => {
    if (isAuthed(props.token)) {
      return <WrappedComponent {...props} />
    }
    return <WrappedComponent {...props} disabled />
  }
}

const DeactivatorInput = ({ style, ...rest }) => (
  <input
    {...rest}
    style={{
      minWidth: 200,
      border: '1px solid rgba(0, 0, 0, 0.5)',
      borderRadius: 4,
      padding: '6px 12px',
      ...style,
    }}
    placeholder="Search a user to deactivate"
  />
)



const DeactivatorInputWithAuthValidation = withAuthValidation(DeactivatorInput)

function App() {
  return (
    <div>
      <DeactivatorInputWithAuthValidation />
    </div>
  )
}

export default App

4. Render Props ile bileşen mantığını yeniden kullanın

hala hatırlıyorum render sahne malzemeleri ilk olarak yüzeye çıkarılıyorduReact topluluğunda hızla trend oldu ve kod mantığını bileşenlerle yeniden kullanmak için yaygın olarak benimsenen bir model haline geldi.

Bu kalıbı kullanmak, daha yüksek dereceli bileşenlerin çözmeye çalıştığı sorunları çözer. Ancak birçok geliştirici, çok iyi bir nedenden dolayı render prop modelini kullanmayı tercih ediyor: Daha yüksek dereceli bileşenler, ihtiyaç duyduğunuz yerde bir sorun yarattı. statik yöntemlerin üzerine kopyala.

Render aksesuarlarının birçok kişi tarafından yoğun bir şekilde tercih edilmesinin bir başka iyi nedeni, gerçekten yeni bir bileşen örneğini örnekle daha yüksek dereceli bileşenlerde yaptığınız gibi. Kalıbı uygulamak için yalnızca tek bir bileşen kullanmanız gerekir (bu, tepki vermek için daha “yerel” bir his verir):

function AuthValidator({ token, render, ...rest }) {
  if (isAuthed(token)) {
    return render({ authenticated: true })
  }
  return render({ authenticated: false })
}

const DeactivatorInput = ({ style, ...rest }) => (
  <input
    {...rest}
    style={{
      minWidth: 200,
      border: '1px solid rgba(0, 0, 0, 0.5)',
      borderRadius: 4,
      padding: '6px 12px',
      ...style,
    }}
    placeholder="Search a user to deactivate"
  />
)

function App() {
  return (
    <div>
      <AuthValidator
        token="abc123"
        render={({ authenticated }) => (
          <DeactivatorInput disabled={!authenticated} />
        )}
      />
    </div>
  )
}

5. Bileşen mantığını çocuklarla işlev olarak yeniden kullanın

Bu temelde render prop yaklaşımını kullanmakla aynıdır, sadece farklı görünür çünkü tepki zaten çocukları açılış bileşeni etiketi ile kapanış etiketi arasına yerleştirir, bu nedenle mantıksal olarak orada kalacaktır:

function AuthValidator({ token, children, ...rest }) {
  if (isAuthed(token)) {
    return children({ authenticated: true })
  }
  return children({ authenticated: false })
}

const DeactivatorInput = ({ style, ...rest }) => (
  <input
    {...rest}
    style={{
      minWidth: 200,
      border: '1px solid rgba(0, 0, 0, 0.5)',
      borderRadius: 4,
      padding: '6px 12px',
      ...style,
    }}
    placeholder="Search a user to deactivate"
  />
)

function App() {
  return (
    <div>
      <AuthValidator token="abc123">
        {({ authenticated }) => <DeactivatorInput disabled={!authenticated} />}
      </AuthValidator>
    </div>
  )
}

6. Bileşen mantığını birden çok oluşturucu işleviyle yeniden kullanın

Bir oluşturma/alt işleviyle sınırlı değilsiniz, birden çok işleve sahip olabilirsiniz:

import React from 'react'
import Topbar from './Topbar'
import Sidebar from './Sidebar'
import About from './About'
import Contact from './Contact'
import PrivacyPolicy from './PrivacyPolicy'
import Dashboard from './Dashboard'
import { Router } from '@reach/router'

function App() {
  return (
    <Router>
      <Dashboard
        topbar={({ authenticated }) => (
          <Router>
            <Topbar path="*" authenticated={authenticated} />
          </Router>
        )}
        sidebar={() => (
          <Router>
            <Sidebar path="*" />
          </Router>
        )}
        view={({ authenticated }) => (
          <Router>
            <About path="/about" />
            <Contact path="/contact" />
            <PrivacyPolicy path="/privacy-policy" />
            <Admin path="/admin" authenticated={authenticated} />
          </Router>
        )}
      />
    </Router>
  )
}

export default App

Ancak bu yaklaşımı gerçekten sevmiyorum ve önermiyorum çünkü render yöntemini yazarken çok sınırlayıcı olabilir. Dashboard. Ancak, kenar çubuğunun veya üst çubuğun kullanıcı arayüzünde başka hiçbir yere hareket etmeyeceği yukarıdaki gibi bir durumda yararlı olabilir.

7. React Hooks ile bileşen mantığını yeniden kullanın

Sonra geldi tepki kancalarıtoplumu bu güne fırtına ile götüren.

Kancalar, yukarıda listelenen sorunlardan herhangi birini çözmenize izin verir ve olması gerektiği gibi çalışarak sizi normal JavaScript’e geri getirir. sadece işlevler:

import React from 'react'

function useStuff() {
  const [data, setData] = React.useState({})

  React.useEffect(() => {
    fetch('https://someapi.com/api/users/')
      .then((response) => setData(response.json()))
      .catch((err) => setData(err))
  }, [])

  return { data, setData }
}

function App() {
  const { data } = useStuff()

  if (data instanceof Error) {
    return <p style={{ color: 'red' }}>Error: {data.message}</p>
  }

  return <div>{JSON.stringify(data, null, 2)}</div>
}

Oluşturulan sahne donanımlarını ortaya çıkaran bir sorun, diğerinin altında iç içe geçmiş birden çok oluşturma donanımı bileşeni oluşturduğumuzda, bir “geri arama cehennemi” şöyle bir şeye bakmak:

import React from 'react'
import ControlPanel from './ControlPanel'
import ControlButton from './ControlButton'

function AuthValidator({ token, render, ...rest }) {
  if (isAuthed(token)) {
    return render({ authenticated: true })
  }
  return render({ authenticated: false })
}

function App() {
  return (
    <div>
      <AuthValidator
        render={({ authenticated }) => {
          if (!authenticated) {
            return null
          }
          return (
            <ControlPanel
              authenticated={authenticated}
              render={({ Container, controls }) => (
                <Container
                  render={({ width, height }) => (
                    <div style={{ width, height }}>
                      {controls.map((options) =>
                        options.render ? (
                          <ControlButton
                            render={({ Component }) => (
                              <Component {...options} />
                            )}
                          />
                        ) : (
                          <ControlButton {...options} />
                        ),
                      )}
                    </div>
                  )}
                />
              )}
            />
          )
        }}
      />
    </div>
  )
}

Kancalarla çalışırken şöyle görünebilir:

import React from 'react'
import useControlPanel from './useControlPanel'
import ControlButton from './ControlButton'

function useAuthValidator({ token }) {
  const [authenticated, setAuthenticated] = React.useState(null)

  React.useEffect(() => {
    if (isAuthed(token)) setAuthenticated(true)
    else setAuthenticated(false)
  })

  return { authenticated }
}

function App() {
  const { authenticated } = useAuthValidator('abc123')
  const { Container, width, height, controls } = useControlPanel({
    authenticated,
  })

  return (
    <Container>
      <div style={{ width, height }}>
        {controls.map((options) =>
          options.render ? (
            <ControlButton
              render={({ Component }) => <Component {...options} />}
            />
          ) : (
            <ControlButton {...options} />
          ),
        )}
      </div>
    </Container>
  )
}

8. Çocuklarla çalışarak bileşen mantığını yeniden kullanın

Hala bazen insanların bir bileşenin belirli bir sahne almadığı zaman nasıl alacağını sorguladığını görüyorum. açıkça şöyle geçti:

const DeactivatorInput = ({
  component: Component = 'input',
  style,
  opened,
  open: openModal,
  close: closeModal,
  ...rest
}) => (
  <div>
    <Component
      type="email"
      onKeyPress={(e) => {
        const pressedEnter = e.charCode === 13
        if (pressedEnter) {
          openModal()
        }
      }}
      style={{
        minWidth: 200,
        border: '1px solid rgba(0, 0, 0, 0.5)',
        borderRadius: 4,
        padding: '6px 12px',
        ...style,
      }}
      placeholder="Search a user to deactivate"
      {...rest}
    />
    <Modal isOpen={opened}>
      <h1>Modal is opened</h1>
      <hr />
      <button type="button" onClick={closeModal}>
        Close
      </button>
    </Modal>
  </div>
)

function App() {
  return (
    <ControlPanel>
      <DeactivatorInput />
    </ControlPanel>
  )
}

Anlaşılan bir soru, bu kodun geçerliliğini sorguluyor, çünkü herhangi bir sahne malzemesinin aktarıldığını görmüyoruz. DeactivatorInputama aslında bir yol var.

Sadece bileşenlere değil, elementlere tepki vermek için gerektiğinde ek sahne malzemeleri enjekte etme yeteneğine sahip olmak güzel. React.cloneElement sizin için tam da bunu yapabilir:

function ControlPanel({ children, ...rest }) {
  const [opened, setOpened] = React.useState(false)
  const open = () => setOpened(true)
  const close = () => setOpened(false)
  return (
    <div>{React.cloneElement(children, { opened, open, close, ...rest })}</div>
  )
}

React ayrıca çocuklarla çalışırken birkaç başka yardımcı program sunar, örneğin: React.Children.toArray ile birlikte kullanabileceğiniz React.cloneElement birden fazla çocuk için:

function ControlPanel({ children, ...rest }) {
  const [opened, setOpened] = React.useState(false)
  const open = () => setOpened(true)
  const close = () => setOpened(false)
  const child = React.Children.toArray(children).map((child) =>
    React.cloneElement(child, { opened, open, close, ...rest }),
  )
  return <div>{child}</div>
}

Bu strateji, uygulamada yaygın olarak kullanıldı. bileşik bileşenler–Ancak, bu benzer işlevselliğe şimdi yaklaşmanın daha iyi bir yolu kullanmaktır. tepki bağlamı çünkü eski çözümün dezavantajları sadece doğrudan çocuklar geçirilen sahne alabilir React.cloneElement iç içe geçmiş her çocukta gerekli olmayan bir özyineleme yapılmadığı sürece. Tepki bağlamıyla, çocukları ne kadar iç içe olurlarsa olsunlar herhangi bir yere yerleştirebilirsiniz ve onlar yine de sizin adınıza senkronize edilebilirler.

Rumble çizelgeleri yoğun olarak kullandığı başarılı bir örnektir. React.Children.map çocuklarının davranışlarına karar vermek için.

9. Dinamik olarak derinlemesine iç içe bileşenler oluşturma

Bu bölümde üzerinde duracağız özyineleme ve reaksiyon bileşenleriyle çalışma sürecini basitleştirmeye nasıl yardımcı olduğunu.

Örneğin, açılır menü olarak bir menü düğmesi içeren bir gezinme çubuğu gibi, yinelenen öğeleri olan bir bileşenimiz olduğunu varsayalım. Bir açılır listede birden fazla öğe olabilir ve her öğenin kendi iç içe açılır menüsü aşağıdaki gibi olabilir:

iç içe menüler özyineleme ile açılır menü tepki

El işçiliği yapmak ve bu iç içe menüleri kendimiz kodlamak istemiyoruz. Yapmamız gereken tek el emeği özyinelemeyi yazmaktır:

import React from 'react'
import Button from '@material-ui/core/Button'
import Menu from '@material-ui/core/Menu'
import MenuItem from '@material-ui/core/MenuItem'
import './styles.css'

const items = [
  { to: '/home', label: 'Home' },
  { to: '/blog', label: 'Blog' },
  { to: '/about', label: 'About' },
  { to: '/contact', label: 'Contact' },
  {
    to: '/help-center',
    label: 'Help Center',
    items: [
      { to: '/privacy-policy', label: 'Privacy Policy' },
      { to: '/tos', label: 'Terms of Service' },
      { to: '/partners', label: 'Partners' },
      {
        to: '/faq',
        label: 'FAQ',
        items: [
          { to: '/faq/newsletter', label: 'Newsletter FAQs' },
          { to: '/faq/career', label: 'Employment/Career FAQs' },
        ],
      },
    ],
  },
]

const MyMenu = React.forwardRef(
  ({ items, anchorEl: anchorElProp, createOnClick, onClose }, ref) => {
    const [anchorEl, setAnchorEl] = React.useState(null)
    return (
      <Menu
        ref={ref}
        open={Boolean(anchorElProp)}
        onClose={onClose}
        anchorEl={anchorElProp}
        anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
        transformOrigin={{ vertical: 'top', horizontal: 'right' }}
      >
        {items.map((item) => (
          <div key={item.to}>
            <MenuItem onMouseEnter={item.items && createOnClick(setAnchorEl)}>
              {item.label}
            </MenuItem>
            {item.items && (
              <MyMenu
                key={item.to}
                items={item.items}
                anchorEl={anchorEl}
                createOnClick={createOnClick}
                onClose={() => setAnchorEl(null)}
              />
            )}
          </div>
        ))}
      </Menu>
    )
  },
)

function App() {
  const [anchorEl, setAnchorEl] = React.useState(null)
  const createOnClick = (callback) => {
    return (e) => {
      e.persist()
      return callback(e.currentTarget)
    }
  }

  return (
    <div>
      <Button onMouseEnter={createOnClick(setAnchorEl)} variant="outlined">
        View More
      </Button>
      <MyMenu
        items={items}
        anchorEl={anchorEl}
        createOnClick={createOnClick}
        onClose={() => setAnchorEl(null)}
      />
    </div>
  )
}

Bunun gibi bileşenler oluşturmak, bileşenlerinizi yeniden kullanılabilir ve dinamik hale getirmenin iyi bir yoludur.

İlgili Makaleler

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.

Başa dön tuşu