模式驱动的React实现更高效的开发

53 阅读3分钟

image.png 我发现React是相当令人愉快的前端技术。然而,有时我觉得我在一个有许多类似/重复元素的组件中重复着相同的老式模板。在这篇文章中,我将向你展示我有时喜欢使用定义组件的模式来简化React开发。

请注意,我将在这篇文章中使用React与Typescript,但这一切在没有类型定义的情况下也同样适用

一个例子。一个长形式的文本区域

假设我们正在开发某种调查应用程序,我们想问许多长形式的问题。我们知道我们需要大量的文本区域来问这些问题,并且我们想把答案存储在一个answers 对象中。

我们的调查将问到一堆不同的食物偏好问题。我们的例子问题将是。

  • 告诉我们你的理想汉堡包
  • 告诉我们你理想的比萨饼
  • 你最喜欢的食物记忆是什么,为什么?

当然,我们可以把这些问题都写成自己的文本区。让我们看看这可能看起来如何。

import React, { useState } from 'react';

const initialAnswers = {
  hamburger: '',
  pizza: '',
  memory: '',
};

function App() {
  const [answers, setAnswers] = useState(initialAnswers);

  return (
    <form>
      <div>
        <label htmlFor="hamburger">Tell us about your ideal hamburger</label>
        <br />
        <textarea
          id="hamburger"
          value={answers.hamburger}
          onChange={(e) => {
            setAnswers({
              ...answers,
              hamburger: e.target.value,
            });
          }}
        />
      </div>
      <div>
        <label htmlFor="pizza">Tell us about your ideal pizza</label>
        <br />
        <textarea
          id="pizza"
          value={answers.pizza}
          onChange={(e) => {
            setAnswers({
              ...answers,
              pizza: e.target.value,
            });
          }}
        />
      </div>
      <div>
        <label htmlFor="memory">
          What is your favorite food memory and why?
        </label>
        <br />
        <textarea
          id="memory"
          value={answers.memory}
          onChange={(e) => {
            setAnswers({
              ...answers,
              memory: e.target.value,
            });
          }}
        />
      </div>
    </form>
  );
}

这很好,也很有效。但是如果我们有大约20个这样的问题呢?我们会在复制这些组件时感到很累。这就是模式方法真正发挥作用的地方。

使用模式来简化重复性的组件开发

与上面的方法相反,让我们做一些优化,使开发不那么乏味。首先,我们要做一个单一的变化处理程序,它可以处理我们表单中任何字段的变化。接下来,我们将创建一个对象数组,每个对象代表我们表单中的一个字段,我们将用它来生成我们所有的问题。

首先,让我们创建那个一致的onChange 处理器。

import React, { useState } from 'react';

const initialAnswers = {
  hamburger: '',
  pizza: '',
  memory: '',
};

type Answers = typeof initialAnswers;

function App() {
  const [answers, setAnswers] = useState(initialAnswers);

  const onChange = <K extends keyof Answers>(key: K, value: Answers[K]) => {
    setAnswers({
      ...answers,
      [key]: value,
    });
  };

  return <></>;
}

接下来,我们可以添加一个字段数组来进行迭代。

import React, { useState } from 'react';

const initialAnswers = {
  hamburger: '',
  pizza: '',
  memory: '',
};

type Answers = typeof initialAnswers;

type Field = {
  key: keyof Answers;
  label: string;
};

const fields: Field[] = [
  { key: 'hamburger', label: 'Tell us about your ideal hamburger' },
  { key: 'pizza', label: 'Tell us about your ideal pizza' },
  { key: 'memory', label: 'What is your favorite food memory and why?' },
];

function App() {
  const [answers, setAnswers] = useState(initialAnswers);

  const onChange = <K extends keyof Answers>(key: K, value: Answers[K]) => {
    setAnswers({
      ...answers,
      [key]: value,
    });
  };

  return <></>;
}

最后,我们可以对数组进行迭代,而不是键入每一个textarea 组件。

import React, { useState } from 'react';

const initialAnswers = {
  hamburger: '',
  pizza: '',
  memory: '',
};

type Answers = typeof initialAnswers;

type Field = {
  key: keyof Answers;
  label: string;
};

const fields: Field[] = [
  { key: 'hamburger', label: 'Tell us about your ideal hamburger' },
  { key: 'pizza', label: 'Tell us about your ideal pizza' },
  { key: 'memory', label: 'What is your favorite food memory and why?' },
];

function App() {
  const [answers, setAnswers] = useState(initialAnswers);

  const onChange = <K extends keyof Answers>(key: K, value: Answers[K]) => {
    setAnswers({
      ...answers,
      [key]: value,
    });
  };

  return (
    <form>
      {fields.map(({ key, label }) => (
        <div key={key}>
          <label htmlFor={key}>{label}</label>
          <br />
          <textarea
            id={key}
            value={answers[key]}
            onChange={(e) => {
              onChange(key, e.target.value);
            }}
          />
        </div>
      ))}
    </form>
  );
}

export default App;

就这样,我们拥有了它!现在我们可以根据需要在我们的数组中添加任意多的字段,新的文本区将被自动地添加到应用程序中。