React Uygulamanızı Geri Alma ve Sıfırlama Yetenekleriyle Geliştirin – JSManifest

final dark

Hiç hata yaptığınız ve olmasını dilediğiniz bir şey geliştirdiniz. geri alma özellik? Ne dersin Sıfırla?

Neyse ki kullandığımız yazılımlarda her zaman geri alma veya sıfırlama özellikleri vardır. konuşuyorum ctrl + z içinde vs koduveya genellikle 90’larda Sıfırla formlarda düğme.

Neden onlara ihtiyacımız var? Eh, çünkü insanlar Her zaman hata yapmak. Yazılı bir makalede yazım hatası mı yoksa yanlış ifade mi olduğu, ihtiyacımız olan bir şekilde bir şeyi geri almak. Yine de düşündüğünüzde, neredeyse bir şeyi geri almanın yolları vardır. her yerde. Kalemlerin silgileri vardır, telefonların parçalarına ayırma yetenekleri vardır, kullanıcılara parolalarını sıfırlama seçeneği sunulur, silinebilir kalemler mürekkebi ovalar – liste uzayıp gidiyor.

Ancak bir geri alma veya sıfırlama özelliği uygulamaya ne dersiniz? bir geliştirici olarak bir uygulama için? Nereden başlarsın? Tavsiye için nereye bakmalısınız?

Pekala, başka yere bakmayın çünkü size uygulamanızı nasıl geliştireceğinizi göstermek için buradayım. geri alma ve Sıfırla yetenekler! Uygulamanın o kadar da zor olmadığını bu makaleden öğreneceksiniz ve sende yapabilirsin.

Yapacağımız şey, kullanıcıların arkadaşlarını adlarına göre ekleyebilecekleri ve arkadaşlarının cinsiyetini belirtebilecekleri bir kullanıcı arayüzü olacak. Arkadaşlar eklendikçe, arkadaşın kayıtlı olduğu bilgileri gösteren kartlar ekrana eklenecektir. Ek olarak, eğer arkadaşları kadınsa, bir sıcak pembe renkli sınır çizgisi, erkeklerde ise deniz mavisi sınırda. Kullanıcı, arkadaşını kaydederken bir hata yaptıysa, geri alma o eylem veya Sıfırla tüm arayüz başlangıç ​​durumuna geri döner. Ve son olarak, karanlık yerine ışıktan hoşlanırlarsa veya tam tersi durumlarda arayüz tema renklerini değiştirebilecekler.

İşte böyle görünecek:

Işık

Karanlık

son karanlık

Lafı fazla uzatmadan başlayalım!

Bu derste, create-react-app ile hızlı bir şekilde bir tepki projesi oluşturacağız.

(Deponun bir kopyasını github’dan almak istiyorsanız, tıklayın burada).

Devam edin ve aşağıdaki komutu kullanarak bir proje oluşturun. Bu eğitim için projemizi arayacağım geri al-sıfırla.

npx create-react-app undo-reset

Şimdi bittiğinde dizine gidin:

Ana girişin içinde src/index.js biraz temizleyeceğiz:

kaynak/index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import './styles.css'
import * as serviceWorker from './serviceWorker'

ReactDOM.render(<App />, document.getElementById('root'))
serviceWorker.unregister()

İşte başlangıç ​​stilleri:

kaynak/styles.css

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
    'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
    'Helvetica Neue', sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

Şimdi oluştur src/App.js. Bu, eğitim boyunca oluşturacağımız tüm bileşenleri oluşturacaktır:

kaynak/App.js

import React, { useState } from 'react'

const App = () => {
  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  return <div />
}

export default App

Kullanıcının arkadaşlarını eklemesine ve isimlerini ve cinsiyetlerini belirtmesine izin vereceğimiz için, giriş değerlerini tutmak için birkaç tepki kancası tanımladık ve bunları güncelleme yöntemlerini de tanımlayacağız.

Ardından, kancaların kendilerini bağlayacağı öğeleri ve giriş alanlarını uygulayacağız:

kaynak/App.js

const App = () => {
  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  return (
    <div>
      <form className="form">
        <div>
          <input
            onChange={onNameChange}
            value={name}
            type="text"
            name="name"
            placeholder="Friend's Name"
          />
        </div>
        <div>
          <select onChange={onGenderChange} name="gender" value={gender}>
            <option value="Male">Male</option>
            <option value="Female">Female</option>
            <option value="Other">Other</option>
          </select>
        </div>
        <div>
          <button type="submit">Add</button>
        </div>
      </form>
    </div>
  )
}

kaynak/styles.css

form {
  display: flex;
  align-items: center;
}

form > div {
  margin: auto 3px;
}

input,
select {
  transition: all 0.15s ease-out;
  border: 1px solid #ddd;
  padding: 10px 14px;
  outline: none;
  font-size: 14px;
  color: #666;
}

input:hover,
select:hover {
  border: 1px solid #c6279f;
}

select {
  cursor: pointer;
  padding-top: 9px;
  padding-bottom: 9px;
}

button {
  transition: all 0.15s ease-out;
  background: #145269;
  border: 1px solid #ddd;
  padding: 10px 35px;
  outline: none;
  cursor: pointer;
  color: #fff;
}

button:hover {
  color: #145269;
  background: #fff;
  border: 1px solid #145269;
}

button:active {
  background: rgb(27, 71, 110);
  border: 1px solid #a1a1a1;
  color: #fff;
}

Artık derslerimde arayüzümü çok sade tutmaktan hoşlanmıyorum–sonuçta, ben yapmak yazılarımı okumaya ayırdığınız zamana değer verin, bu yüzden sizi can sıkıntısından uzak tutmak için stiller hakkında biraz düşündüm 🙂

Ardından, geri alma ve sıfırlama mantığını koymak için sağlam bir yere ihtiyacımız var, bu nedenle durum güncellemelerini işleyecek özel bir kanca oluşturacağız:

src/useApp.js

const useApp = () => {
  const onSubmit = (e) => {
    e.preventDefault()
    console.log('Submitted')
  }

  return {
    onSubmit,
  }
}

export default useApp

bu onSubmit yukarıda aktarılacak biçim Kullanıcı onları gönderdiğinde arkadaş listesine arkadaş eklemeye yardımcı olacak daha önce tanımlamıştık:

kaynak/App.js

import React, { useState } from 'react'
import useApp from './useApp'

const App = () => {
  const { onSubmit } = useApp()

  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  return (
    <div>
      <form className="form" onSubmit={onSubmit({ name, gender })}>
        <div>
          <input
            onChange={onNameChange}
            value={name}
            type="text"
            name="name"
            placeholder="Friend's Name"
          />
        </div>
        <div>
          <select onChange={onGenderChange} name="gender" value={gender}>
            <option value="Male">Male</option>
            <option value="Female">Female</option>
            <option value="Other">Other</option>
          </select>
        </div>
        <div>
          <button type="submit">Add</button>
        </div>
      </form>
    </div>
  )
}

export default App

Burada dikkat edilmesi gereken bir şey onSubmit alan parametreleri argüman olarak verilir. arkamıza bakarsak onSubmit işleyici o değil üst düzey fonksiyon. Bu, bileşen takıldığında hemen çağrılacağı anlamına gelir, bu nedenle onSubmit işleyicisini, alanların değerlerini alma yeteneği vermenin yanı sıra, bunu atlamak için daha yüksek dereceli bir işleve dönüştürmemiz gerekir:

src/useApp.js

const useApp = () => {
  const onSubmit = (friend) => (e) => {
    e.preventDefault()
    console.log(friend)
  }

  return {
    onSubmit,
  }
}

export default useApp

Şimdiye kadar, elimizde bu var:

Sonra mantığı uygulamaya başlayacağız. Ama önce, tanımlamamız gerekiyor devlet yapısı:

src/useApp.js

const initialState = {
  friends: [],
  history: [],
}

Bu eğitimin en önemli kısmı, Tarih. Kullanıcı bir işlem gönderdiğinde, ele geçirmek uygulamanın durumu ve daha sonra kullanıcı işlemlerini geri almak için başvurabileceğimiz bir yerde güvenli bir şekilde saklayın. Bu “depolamak” dır-dir durum.tarih Hangi sadece özel kancamızın bilmesi gerekiyor. Bununla birlikte, kullanıcı arayüzünde ilginç işlevsellik için de kullanılabilir – örneğin, kullanıcının önceki eylemlerini bir ızgara aracılığıyla görüntülemesine izin vermek ve seçme hangisine dönelim. Bu kullanışlı küçük bir özellik vay kullanıcılarınız!

Ardından, durumumuzun gerçekten güncellenebilmesi için redüktördeki anahtar durumlarını ekleyeceğiz:

src/useApp.js

const reducer = (state, action) => {
  switch (action.type) {
    case 'add-friend':
      return {
        ...state,
        friends: [...state.friends, action.friend],
        history: [...state.history, state],
      }
    case 'undo': {
      const isEmpty = !state.history.length
      if (isEmpty) return state
      return { ...state.history[state.history.length - 1] }
    }
    default:
      return state
  }
}

Biz ne zaman sevk türü olan bir eylem ‘arkadaş Ekle’, devam ettik ve yeni arkadaşı listeye ekledik. Ama ne kullanıcı bilmiyor öyle miyiz önceki düzenlemelerini sessizce kaydediyor. Uygulamanın en son durumunu yakaladık ve Tarih dizi. Bu şekilde, kullanıcı önceki bir duruma geri dönmek isterse, bunu gerçekleştirmelerine yardımcı olabiliriz 🙂

Bir tepki kancası api kullandığımız için, onu içe aktarmayı unutmamalıyız. tepki. ayrıca tanımlamamız gerekiyor kullanımRedüktör yerel durumumuzu güncellemek için sinyaller gönderecek api’yi elde etmemiz için özel kancamızın içindeki uygulama:

src/useApp.js

import { useReducer } from 'react'


const [state, dispatch] = useReducer(reducer, initialState)

Artık apis’i edindiğimize göre, onları ihtiyacı olan yerlere dahil edelim:

src/useApp.js

const onSubmit = (friend) => (e) => {
  e.preventDefault()
  if (!friend.name) return
  dispatch({ type: 'add-friend', friend })
}

const undo = () => {
  dispatch({ type: 'undo' })
}

Özel kancamız şu ana kadar şöyle görünüyor:

src/useApp.js

import { useReducer } from 'react'

const initialState = {
  friends: [],
  history: [],
}

const reducer = (state, action) => {
  switch (action.type) {
    case 'add-friend':
      return {
        ...state,
        friends: [...state.friends, action.friend],
        history: [...state.history, state],
      }
    case 'undo': {
      const isEmpty = !state.history.length
      if (isEmpty) return state
      return { ...state.history[state.history.length - 1] }
    }
    default:
      return state
  }
}

const useApp = () => {
  const [state, dispatch] = useReducer(reducer, initialState)

  const onSubmit = (friend) => (e) => {
    e.preventDefault()
    if (!friend.name) return
    dispatch({ type: 'add-friend', friend })
  }

  const undo = () => {
    dispatch({ type: 'undo' })
  }

  return {
    ...state,
    onSubmit,
    undo,
  }
}

export default useApp

Ardından, eklenen arkadaş listesini oluşturmamız gerekecek. devlet.arkadaşlar kullanıcının bunları arayüzde görebilmesi için:

kaynak/App.js

const App = () => {
  const { onSubmit, friends } = useApp()

  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  return (
    <div>
      <form className="form" onSubmit={onSubmit({ name, gender })}>
        <div>
          <input
            onChange={onNameChange}
            value={name}
            type="text"
            name="name"
            placeholder="Friend's Name"
          />
        </div>
        <div>
          <select onChange={onGenderChange} name="gender" value={gender}>
            <option value="Male">Male</option>
            <option value="Female">Female</option>
            <option value="Other">Other</option>
          </select>
        </div>
        <div>
          <button type="submit">Add</button>
        </div>
      </form>
      <div className="boxes">
        {friends.map(({ name, gender }, index) => (
          <FriendBox key={`friend_${index}`} gender={gender}>
            <div className="box-name">Name: {name}</div>
            <div className="gender-container">
              <img src={gender === 'Female' ? female : male} alt="" />
            </div>
          </FriendBox>
        ))}
      </div>
    </div>
  )
}

Bu tuhaf çizginin ne yaptığını merak ediyorsanız:

<img src={gender === 'Female' ? female : male} alt="" />

Aslında sadece kendi resimlerimi üzerinde işlemek için sağladım. resim arasında kolayca ayrım yapabilmek için dişi ve erkek arayüzde–gösteri amaçlı. Depoyu klonlayanlarınız onları şurada görebilecektir. kaynak/görüntüler bunların bir kopyasına ihtiyacınız varsa dizin 🙂

Üst kısımdaki kadın/erkek resimlerini içe aktarıyoruz. App.jsve hemen üstünde Uygulama bileşen tanımlayacağız Arkadaş Kutusu oluşturulmasından sorumlu olacak bileşen arkadaş kullanıcı listeye eklerken kutu:

kaynak/App.js


import female from './images/female.jpg'
import male from './images/male.jpg'


const FriendBox = ({ gender, ...props }) => (
  <div
    className={cx('box', {
      'teal-border': gender === 'Male',
      'hotpink-border': gender === 'Female',
    })}
    {...props}
  />
)

arasında daha fazla ayrım yapmak için dişi ve erkek görsel bir bakış açısıyla, her birini temsil etmek için ayrıca temel stiller ekledim:

kaynak/styles.css

.teal-border {
  border: 1px solid #467b8f;
}

.hotpink-border {
  border: 1px solid #c1247d;
}

Ve burada şimdiye kadar sahip olduklarımız App.js dosya:

kaynak/App.js

import React, { useState } from 'react'
import cx from 'classnames'
import female from './images/female.jpg'
import male from './images/male.jpg'
import useApp from './useApp'

const FriendBox = ({ gender, ...props }) => (
  <div
    className={cx('box', {
      'teal-border': gender === 'Male',
      'hotpink-border': gender === 'Female',
    })}
    {...props}
  />
)

const App = () => {
  const { onSubmit, friends } = useApp()

  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  return (
    <div>
      <form className="form" onSubmit={onSubmit({ name, gender })}>
        <div>
          <input
            onChange={onNameChange}
            value={name}
            type="text"
            name="name"
            placeholder="Friend's Name"
          />
        </div>
        <div>
          <select onChange={onGenderChange} name="gender" value={gender}>
            <option value="Male">Male</option>
            <option value="Female">Female</option>
            <option value="Other">Other</option>
          </select>
        </div>
        <div>
          <button type="submit">Add</button>
        </div>
      </form>
      <div className="boxes">
        {friends.map(({ name, gender }, index) => (
          <FriendBox key={`friend_${index}`} gender={gender}>
            <div className="box-name">Name: {name}</div>
            <div className="gender-container">
              <img src={gender === 'Female' ? female : male} alt="" />
            </div>
          </FriendBox>
        ))}
      </div>
    </div>
  )
}

export default App

Buradaki kutular için kullanılan stiller şunlardır:

kaynak/styles.css

.boxes {
  margin: 10px 0;
  padding: 3px;
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 1fr;
}

.box {
  font-size: 18px;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.box-name {
  display: flex;
  align-items: center;
  height: 50px;
}

.box.gender-container {
  position: relative;
}

.box img {
  object-fit: cover;
  width: 100%;
  height: 100%;
}

Ah, serseri! Yapmayı unuttuğumuz bir şey, geri alma yöntem, böylece arayüzde kullanabiliriz! Devam et ve onu yok et uygulama ve üzerine yerleştirin Geri alma buton:

kaynak/App.js

const App = () => {
  const { onSubmit, friends, undo } = useApp()

  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  const resetValues = () => {
    setName('')
    setGender('Male')
  }

  return (
    <div>
      <form className="form" onSubmit={onSubmit({ name, gender }, resetValues)}>
        <div>
          <input
            onChange={onNameChange}
            value={name}
            type="text"
            name="name"
            placeholder="Friend's Name"
          />
        </div>
        <div>
          <select onChange={onGenderChange} name="gender" value={gender}>
            <option value="Male">Male</option>
            <option value="Female">Female</option>
            <option value="Other">Other</option>
          </select>
        </div>
        <div>
          <button type="submit">Add</button>
        </div>
      </form>
      <div className="undo-actions">
        <div>
          <button type="button" onClick={undo}>
            Undo
          </button>
        </div>
      </div>
      <div className="boxes">
        {friends.map(({ name, gender }, index) => (
          <FriendBox key={`friend_${index}`} gender={gender}>
            <div className="box-name">Name: {name}</div>
            <div className="gender-container">
              <img src={gender === 'Female' ? female : male} alt="" />
            </div>
          </FriendBox>
        ))}
      </div>
    </div>
  )
}

Şimdi kullanıcı tıkladığında Geri alma düğmesi, son eylemleri geri yüklenmelidir!

2

Her şey planlandığı gibi mükemmel gidiyor. Kullanıcı, arkadaşlarını listeye ekleyebiliyor, arayüzde hangilerinin kadın hangilerinin erkek olduğunu kolayca görebiliyor ve önceki gönderilerini geri alabiliyor.

…aynı zamanda fark ettiniz mi? resetValues yöntemde Uygulama bileşen, geçirildiği yer onSubmit ikinci argüman olarak? Kullanıcılara biraz garip gelebilecek bir şey, bir arkadaş gönderdikten sonra girdilerinin netleşmemesidir. Orada hala aynı isme ihtiyaçları var mı? Aynı ada sahip iki veya üç arkadaşı olmadığı sürece, geri al düğmesine basacaklarından ve kendilerini temizleyeceklerinden eminler. Ancak biz geliştiriciler olarak hayatlarını kolaylaştırma yeteneğine sahibiz, bu yüzden bir resetValues.

Bunu söyledikten sonra, olarak ilan edilmelidir. ikinci parametre ile onSubmit olarak geçtiğimizden beri ikinci argüman UI bileşeninde:

src/useApp.js

const useApp = () => {
  const [state, dispatch] = useReducer(reducer, initialState)

  const onSubmit = (friend, resetValues) => (e) => {
    e.preventDefault()
    if (!friend.name) return
    dispatch({ type: 'add-friend', friend })
    resetValues()
  }

  const undo = () => {
    dispatch({ type: 'undo' })
  }

  return {
    ...state,
    onSubmit,
    undo,
  }
}

Geri alma özelliğimiz şimdiye kadar %100 iyi çalışıyor olmalı, ancak bunu biraz daha karmaşık hale getirmek için biraz daha ileri gideceğim çünkü bir geri alma hemen her şeyle uyumlu olabilir.

Bu nedenle, kullanıcının beyazdan çok sıkılmaması için arayüz için bir tema rengi belirlemesine izin vereceğiz:

src/useApp.js

const initialState = {
  friends: [],
  history: [],
  theme: 'light',
}

src/useApp.js

const reducer = (state, action) => {
  switch (action.type) {
    case 'set-theme':
      return { ...state, theme: action.theme, history: insertToHistory(state) }
    case 'add-friend':
      return {
        ...state,
        friends: [...state.friends, action.friend],
        history: insertToHistory(state),
      }
    case 'undo': {
      const isEmpty = !state.history.length
      if (isEmpty) return state
      return { ...state.history[state.history.length - 1] }
    }
    case 'reset':
      return { ...initialState, history: insertToHistory(state) }
    default:
      return state
  }
}

Ayrıca ilan verdim Tarihe Ekle Yukarıda fark etmiş olabileceğiniz gibi, durum argümanı için gelecekte garip bir değere geçmemiz durumunda bize ekstra faydalar sağlayacak yardımcı program:

const insertToHistory = (state) => {
  if (state && Array.isArray(state.history)) {
    
    const newHistory = [...state.history]
    newHistory.push(state)
    return newHistory
  }
  console.warn(
    'WARNING! The state was attempting capture but something went wrong. Please check if the state is controlled correctly.',
  )
  return state.history || []
}

Uygulamanız geliştikçe ileriyi düşünmenin çok önemli bir alışkanlık olduğunu eklemek isterim. daha büyük ve daha karmaşık.

Şimdi ile devam ediyor tema uygulamasıkullanıcı arayüzü bileşenlerinin yararlanabileceği özel bir yöntem tanımlayacağız:

src/useApp.js

const onThemeChange = (e) => {
  dispatch({ type: 'set-theme', theme: e.target.value })
}

return {
  ...state,
  onSubmit,
  undo,
  onThemeChange,
}

Tema bileşenlerinin ve yöntemin arayüze uygulanması:

kaynak/App.js

import React, { useState } from 'react'
import cx from 'classnames'
import female from './images/female.jpg'
import male from './images/male.jpg'
import useApp from './useApp'

const FriendBox = ({ gender, ...props }) => (
  <div
    className={cx('box', {
      'teal-border': gender === 'Male',
      'hotpink-border': gender === 'Female',
    })}
    {...props}
  />
)

const App = () => {
  const { onSubmit, friends, undo, theme, onThemeChange } = useApp()

  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  const resetValues = () => {
    setName('')
    setGender('Male')
  }

  return (
    <div>
      <div>
        <h3>What theme would you like to display?</h3>
        <div>
          <select onChange={onThemeChange} name="theme" value={theme}>
            <option value="light">Light</option>
            <option value="dark">Dark</option>
          </select>
        </div>
      </div>
      <div>
        <h3>Add a friend</h3>
        <form
          className="form"
          onSubmit={onSubmit({ name, gender }, resetValues)}
        >
          <div>
            <input
              onChange={onNameChange}
              value={name}
              type="text"
              name="name"
              placeholder="Friend's Name"
            />
          </div>
          <div>
            <select onChange={onGenderChange} name="gender" value={gender}>
              <option value="Male">Male</option>
              <option value="Female">Female</option>
              <option value="Other">Other</option>
            </select>
          </div>
          <div>
            <button type="submit">Add</button>
          </div>
        </form>
      </div>
      <div>
        <h3>Made a mistake?</h3>
        <div className="undo-actions">
          <div>
            <button type="button" onClick={undo}>
              Undo
            </button>
          </div>
        </div>
      </div>
      <div className="boxes">
        {friends.map(({ name, gender }, index) => (
          <FriendBox key={`friend_${index}`} gender={gender}>
            <div className="box-name">Name: {name}</div>
            <div className="gender-container">
              <img src={gender === 'Female' ? female : male} alt="" />
            </div>
          </FriendBox>
        ))}
      </div>
    </div>
  )
}

export default App

eklediğimizden beri tema özelliği değiştiriyorsa, değişikliklere uyum sağlamak için bazı koşullu stiller eklemek muhtemelen iyi bir fikirdir, değil mi?

 <div className={cx({
    'theme-light': theme === 'light',
    'theme-dark': theme === 'dark',
  })}
  

Ve işte bunun için stiller:

kaynak/styles.css

.theme-light,
.theme-dark {
  box-sizing: border-box;
  transition: all 0.15s ease-out;
  padding: 12px;
  min-height: 100vh;
}

.theme-light {
  color: #145269;
  background: #fff;
}

.theme-dark {
  color: #fff;
  background: #0b2935;
}

Mükemmel! Arayüzümüzün şimdi yapabilecekleri burada!

3

Buraya kadar gelebildiğiniz için kendinize bir alkış verin!

Henüz kutlamayalım, çünkü bu makalenin başlığı da bir Sıfırla Arayüz için özellik.

Şimdi bunu, şu anda sahip olduğumuz redüktördeki anahtar durumunu tanımlayarak yapalım:

src/useApp.js

const reducer = (state, action) => {
  switch (action.type) {
    case 'set-theme':
      return { ...state, theme: action.theme, history: insertToHistory(state) }
    case 'add-friend':
      return {
        ...state,
        friends: [...state.friends, action.friend],
        history: insertToHistory(state),
      }
    case 'undo': {
      const isEmpty = !state.history.length
      if (isEmpty) return state
      return { ...state.history[state.history.length - 1] }
    }
    case 'reset':
      return { ...initialState, history: insertToHistory(state) }
    default:
      return state
  }
}

Şimdi elbette bunun anlamı, durum değişikliği için bu redüktörü işaret edecek yöntemi tanımlamak zorunda olmaktır. Kancanın sonunda iade etmeyi unutmayın!

src/useApp.js

const reset = () => {
  dispatch({ type: 'reset' })
}

const onThemeChange = (e) => {
  dispatch({ type: 'set-theme', theme: e.target.value })
}

return {
  ...state,
  onSubmit,
  onThemeChange,
  undo,
  reset,
}

UI bileşenindeki kancadan yok etmek:

kaynak/App.js

const { onSubmit, friends, undo, theme, onThemeChange, reset } = useApp()

kaynak/App.js

<div>
  <h3>Made a mistake?</h3>
  <div className="undo-actions">
    <div>
      <button type="button" onClick={undo}>
        Undo
      </button>
    </div>
    <div>
      <button type="button" onClick={reset}>
        Reset
      </button>
    </div>
  </div>
</div>

Son olarak, bu eylemleri yatay olarak hizalamak için kullanılan stiller:

kaynak/styles.css

.undo-actions {
  display: flex;
  align-items: center;
}

.undo-actions > div {
  margin: auto 3px;
}

Sonuç:

4

Arayüzün sıfırlanmasının da nasıl yakalandığını sevmiyor musunuz? geri alma?

Depoyu indirip klonlamayı seçtiyseniz, aşağıda gösterildiği gibi küçük değişiklikler göreceksiniz:

kaynak/App.js

import React, { useState } from 'react'
import cx from 'classnames'
import useApp from './useApp'
import ThemeControl from './ThemeControl'
import AddFriend from './AddFriend'
import UndoResetControl from './UndoResetControl'
import Friends from './Friends'
import './styles.css'

const App = () => {
  const { friends, theme, onSubmit, onThemeChange, undo, reset } = useApp()

  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  const resetValues = () => {
    setName('')
    setGender('Male')
  }

  return (
    <div
      className={cx({
        'theme-light': theme === 'light',
        'theme-dark': theme === 'dark',
      })}
    >
      <ThemeControl theme={theme} onChange={onThemeChange} />
      <AddFriend
        onSubmit={onSubmit({ name, gender }, resetValues)}
        onNameChange={onNameChange}
        onGenderChange={onGenderChange}
        currentValues={{ name, gender }}
      />
      <UndoResetControl undo={undo} reset={reset} />
      <Friends friends={friends} />
    </div>
  )
}

export default App

O aynı Bileşenleri kendi dosyalarına ayırarak biraz daha okunabilir ve bakımı yapılabilir olacak şekilde düzenledim.

Bonus

Eğiticinin başında, kullanıcılara görüntüleyebileceğiniz bir arayüzden bahsetmiştim – onlara, istenirse uygulamanın hangi önceki durumuna geri dönebileceklerini seçme seçeneği verdim. İşte kullanımda buna bir örnek:

bonus

Çözüm

Bir şeyleri geri almak bizim için çok faydalıdır çünkü biz insanlar hata yapmaktan asla vazgeçmeyiz… hadi gerçekle yüzleşelim. Umarım bu, bunun sizin için gerçekten yararlı olduğunu düşündüğünüz anlamına gelir 🙂

Bir dahaki sefere görüşürüz çocuklar ve gelecekte benden daha fazla okumak istiyorsanız beni takip edebilirsiniz!

Bir cevap yazın

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