محبوب ترین راه برای مدیریت حالت برنامه مشترک در React استفاده از چارچوبی مانند Redux است. به تازگی ، تیم React چندین ویژگی جدید ارائه کرده است که شامل آنها می شود واکنش به قلاب ها و Context API. این دو ویژگی به طور موثری بسیاری از چالش هایی را که توسعه دهندگان پروژه های بزرگ React با آن روبرو بوده اند برطرف می کند. یکی از بزرگترین مشکلات “سوراخکاری” بود که با اجزای تو در تو معمول بود. راه حل استفاده از کتابخانه مدیریت دولتی مانند Redux بود. متأسفانه این امر با هزینه نوشتن کد دیگ بخار انجام شد. اما اکنون امکان جایگزینی Redux با React Hooks و Context API وجود دارد.

در این آموزش ، شما می خواهید یک روش جدید برای مدیریت وضعیت در پروژه های React خود ، بدون نوشتن کد بیش از حد یا نصب مجموعه ای از کتابخانه ها – همانطور که در Redux رخ می دهد – یاد بگیرید. قلاب های React به شما امکان می دهد از حالت محلی در داخل اجزای عملکرد استفاده کنید ، در حالی که Context API به شما امکان می دهد حالت را با سایر اجزا به اشتراک بگذارید.

پیش نیازها

برای پیگیری این آموزش ، باید با مباحث زیر آشنا شوید:

تکنیکی که در اینجا خواهید آموخت بر اساس الگوهایی است که در Redux معرفی شده اند. این بدان معنی است که شما باید درک درستی از آن داشته باشید reducers و actions قبل از اقدام من در حال حاضر استفاده می کنم Visual Studio Code، که به نظر می رسد محبوب ترین ویرایشگر کد در حال حاضر (به ویژه برای توسعه دهندگان JavaScript) باشد. اگر از ویندوز استفاده می کنید ، توصیه می کنم نصب کنید گیت باش. برای اجرای کلیه دستورات ارائه شده در این آموزش از ترمینال Git Bash استفاده کنید. Cmder همچنین ترمینال خوبی است که قادر به اجرای بیشتر دستورات لینوکس در ویندوز است.

در این قسمت می توانید به پروژه کامل مورد استفاده در این آموزش دسترسی پیدا کنید مخزن GitHub.

درباره روش مدیریت دولت جدید

دو نوع دولت وجود دارد که باید در پروژه های React با آنها کنار بیاییم:

ایالات محلی را فقط می توان در م componentsلفه هایی که تعریف شده اند استفاده کرد. دولت های جهانی را می توان در چندین ملفه به اشتراک گذاشت. پیش از این ، تعریف یک کشور جهانی مستلزم نصب چارچوب مدیریت ایالتی بود ردوکس یا MobX. با واکنش v16.3.0، Context API منتشر شد ، که به توسعه دهندگان اجازه می دهد بدون نصب کتابخانه اضافی ، وضعیت جهانی را پیاده سازی کنند.

از همان زمان به v16.8 واکنش نشان دهید، قلاب اجازه اجرای تعدادی از ویژگیهای React را در یک م componentلفه بدون نوشتن کلاس داده اند. هوک مزایای زیادی برای نحوه نوشتن کد توسط توسعه دهندگان React به همراه داشت. این شامل استفاده مجدد از کد و روشهای آسانتر تقسیم حالت بین اجزا است. برای این آموزش ، ما به React hooks زیر توجه خواهیم کرد:

useState برای استفاده از مقادیر ساده مانند اعداد یا رشته ها توصیه می شود. با این حال ، وقتی نوبت به مدیریت ساختارهای پیچیده داده می رسد ، شما به آن نیاز خواهید داشت useReducer قلاب. برای useState، شما فقط باید یک تک داشته باشید setValue() تابع برای رونویسی مقادیر حالت موجود.

برای useReducer، شما یک شی state دولتی را مدیریت خواهید کرد که شامل چندین مقدار با انواع مختلف داده در یک ساختار درخت مانند است. باید عملکردهایی را اعلام کنید که می توانند یک یا چند مورد از این مقدارها را تغییر دهند. برای انواع داده ها مانند آرایه ها ، باید چندین عملکرد غیر قابل تغییر را برای مدیریت اعمال ، به روز رسانی و حذف اعلام کنید. نمونه ای از این مورد را در بخش بعدی این آموزش مشاهده خواهید کرد.

پس از اعلام وضعیت خود با استفاده از هر یک از آنها useState یا useReducer، برای تبدیل شدن به حالت جهانی با استفاده از React Context ، باید آن را بلند کنید. این کار با ایجاد a انجام می شود متن زمینه با استفاده از createContext عملکرد ارائه شده توسط کتابخانه React. یک شی context زمینه ای اجازه می دهد تا دولت بدون استفاده از غرفه ها در میان اجزا به اشتراک گذاشته شود.

همچنین باید a را اعلام کنید ارائه دهنده متن برای شی context زمینه شما. این اجازه می دهد تا یک صفحه یا یک م containerلفه کانتینر برای تغییر در شی context زمینه شما مشترک شود. هر یک از اجزای کودک کانتینر قادر خواهد بود با استفاده از useContext تابع.

حالا بیایید کد را در عمل ببینیم.

راه اندازی پروژه

ما استفاده خواهیم کرد ایجاد-واکنش-برنامه برای شروع سریع پروژه ما:

$ npx create-react-app react-hooks-context-app

بعد ، بیایید نصب کنیم واکنش UI معنایی، یک چارچوب CSS مبتنی بر React. این یک الزام نیست. من فقط ایجاد رابط کاربری خوب بدون نوشتن CSS سفارشی را دوست دارم:

yarn add semantic-ui-react fomantic-ui-css

باز کن src/index.js واردات زیر را وارد کنید:

import 'fomantic-ui-css/semantic.min.css';

این همان کاری است که برای شروع استفاده از UI معنایی در پروژه خود باید انجام دهیم. در بخش بعدی ، بررسی خواهیم کرد که چگونه می توان با استفاده از useState قلاب کردن و بالا بردن آن به حالت جهانی.

شمارنده شمارنده: useState

برای این مثال ، ما یک نسخه نمایشی ساده متشکل از یک جز two دو دکمه ای و یک جز display نمایشگر خواهیم ساخت. ما معرفی خواهیم کرد count حالتی که در سطح جهانی بین دو م componentsلفه تقسیم خواهد شد. م Theلفه ها فرزند آن خواهند بود CounterView، که به عنوان ظرف عمل خواهد کرد. م componentلفه دکمه دارای دکمه هایی است که مقدار آن را افزایش یا کاهش می دهد count دولت.

بیایید با تعریف خود شروع کنیم count در یک پرونده زمینه به نام context/counter-context.js. این را در داخل ایجاد کنید src پوشه را وارد کرده و کد زیر را وارد کنید:

import React, { useState, createContext } from "react";


export const CounterContext = createContext();


export const CounterContextProvider = props => {
  const [count, setCount] = useState(0);

  return (
    <CounterContext.Provider value={[count, setCount]}>
      {props.children}
    </CounterContext.Provider>
  );
};

ما حالتی را تعریف کرده ایم به نام count و مقدار پیش فرض را روی قرار دهید 0. تمام اجزای مصرف کننده CounterContext.Provider دسترسی به count دولت و setCount تابع. بیایید برای نمایش مولفه تعریف کنیم count دولت در src/components/counter-display.js:

import React, { useContext } from "react";
import { Statistic } from "semantic-ui-react";
import { CounterContext } from "../context/counter-context";

export default function CounterDisplay() {
  const [count] = useContext(CounterContext);

  return (
    <Statistic>
      <Statistic.Value>{count}</Statistic.Value>
      <Statistic.Label>Counter</Statistic.Label>
    </Statistic>
  );
}

در مرحله بعد ، بیایید م componentلفه ای را تعریف کنیم که شامل دکمه های افزایش و کاهش مقدار باشد state جزء. پرونده را ایجاد کنید src/components/counter-buttons.js و کد زیر را وارد کنید:

import React, { useContext } from "react";
import { Button } from "semantic-ui-react";
import { CounterContext } from "../context/counter-context";

export default function CounterButtons() {
  const [count, setCount] = useContext(CounterContext);

  const increment = () => {
    setCount(count + 1);
  };

  const decrement = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <Button.Group>
        <Button color="green" onClick={increment}>
          Add
        </Button>
        <Button color="red" onClick={decrement}>
          Minus
        </Button>
      </Button.Group>
    </div>
  );
}

همانطور که هست ، useContext تابع کار نخواهد کرد ، زیرا ما مشخص نکرده ایم تامین کننده. بیایید این کار را با ایجاد یک ظرف در داخل انجام دهیم src/views/counter-view.js. کد زیر را وارد کنید:

import React from "react";
import { Segment } from "semantic-ui-react";

import { CounterContextProvider } from "../context/counter-context";
import CounterDisplay from "../components/counter-display";
import CounterButtons from "../components/counter-buttons";

export default function CounterView() {
  return (
    <CounterContextProvider>
      <h3>Counter</h3>
      <Segment textAlign="center">
        <CounterDisplay />
        <CounterButtons />
      </Segment>
    </CounterContextProvider>
  );
}

در آخر ، اجازه دهید کد موجود را در جایگزین کنیم App.js با موارد زیر:

import React from "react";
import { Container } from "semantic-ui-react";

import CounterView from "./views/counter-view";

export default function App() {
  return (
    <Container>
      <h1>React Hooks Context Demo</h1>
      <CounterView />
    </Container>
  );
}

اکنون می توانید create-react-app سرور با استفاده از yarn start فرمان دادن مرورگر باید پیشخوان شما را شروع کرده و ارائه دهد. برای اطمینان از این موضوع روی دکمه ها کلیک کنید increment و decrement توابع کار می کنند.

همچنین می توانید این کد را روی CodePen تست کنید.

قلم را ببینید
qBZYyqw
توسط SitePoint (SitePoint)
بر CodePen.

بیایید به بخش بعدی برویم ، در اینجا مثالی را تنظیم می کنیم که با استفاده از کمی پیشرفته تر است useReducer قلاب.

در این مثال ، ما یک صفحه CRUD اساسی برای مدیریت مخاطبین ایجاد خواهیم کرد. از چند م componentsلفه ارائه و یک ظرف ساخته خواهد شد. همچنین یک شی زمینه برای مدیریت وضعیت مخاطبین وجود خواهد داشت. از آنجا که درخت حالت ما کمی پیچیده تر از مثال قبلی است ، بنابراین ما مجبور به استفاده از useReducer قلاب.

شی context زمینه ای را ایجاد کنید src/context/contact-context.js و این کد را وارد کنید:

import React, { useReducer, createContext } from "react";

export const ContactContext = createContext();

const initialState = {
  contacts: [
    {
      id: "098",
      name: "Diana Prince",
      email: "diana@us.army.mil"
    },
    {
      id: "099",
      name: "Bruce Wayne",
      email: "bruce@batmail.com"
    },
    {
      id: "100",
      name: "Clark Kent",
      email: "clark@metropolitan.com"
    }
  ],
  loading: false,
  error: null
};

const reducer = (state, action) => {
  switch (action.type) {
    case "ADD_CONTACT":
      return {
        contacts: [...state.contacts, action.payload]
      };
    case "DEL_CONTACT":
      return {
        contacts: state.contacts.filter(
          contact => contact.id !== action.payload
        )
      };
    case "START":
      return {
        loading: true
      };
    case "COMPLETE":
      return {
        loading: false
      };
    default:
      throw new Error();
  }
};

export const ContactContextProvider = props => {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <ContactContext.Provider value={[state, dispatch]}>
      {props.children}
    </ContactContext.Provider>
  );
};

مولفه اصلی را ایجاد کنید src/views/contact-view.js و این کد را وارد کنید:

import React from "react";
import { Segment, Header } from "semantic-ui-react";
import ContactForm from "../components/contact-form";
import ContactTable from "../components/contact-table";
import { ContactContextProvider } from "../context/contact-context";

export default function Contacts() {
  return (
    <ContactContextProvider>
      <Segment basic>
        <Header as="h3">Contacts</Header>
        <ContactForm />
        <ContactTable />
      </Segment>
    </ContactContextProvider>
  );
}

م presentationلفه ارائه را ایجاد کنید src/components/contact-table.js و این کد را وارد کنید:

import React, { useState, useContext } from "react";
import { Segment, Table, Button, Icon } from "semantic-ui-react";
import { ContactContext } from "../context/contact-context";

export default function ContactTable() {
  
  const [state, dispatch] = useContext(ContactContext);
  
  const [selectedId, setSelectedId] = useState();

  const delContact = id => {
    dispatch({
      type: "DEL_CONTACT",
      payload: id
    });
  };

  const onRemoveUser = () => {
    delContact(selectedId);
    setSelectedId(null); 
  };

  const rows = state.contacts.map(contact => (
    <Table.Row
      key={contact.id}
      onClick={() => setSelectedId(contact.id)}
      active={contact.id === selectedId}
    >
      <Table.Cell>{contact.id}</Table.Cell>
      <Table.Cell>{contact.name}</Table.Cell>
      <Table.Cell>{contact.email}</Table.Cell>
    </Table.Row>
  ));

  return (
    <Segment>
      <Table celled striped selectable>
        <Table.Header>
          <Table.Row>
            <Table.HeaderCell>Id</Table.HeaderCell>
            <Table.HeaderCell>Name</Table.HeaderCell>
            <Table.HeaderCell>Email</Table.HeaderCell>
          </Table.Row>
        </Table.Header>
        <Table.Body>{rows}</Table.Body>
        <Table.Footer fullWidth>
          <Table.Row>
            <Table.HeaderCell />
            <Table.HeaderCell colSpan="4">
              <Button
                floated="right"
                icon
                labelPosition="left"
                color="red"
                size="small"
                disabled={!selectedId}
                onClick={onRemoveUser}
              >
                <Icon name="trash" /> Remove User
              </Button>
            </Table.HeaderCell>
          </Table.Row>
        </Table.Footer>
      </Table>
    </Segment>
  );
}

م presentationلفه ارائه را ایجاد کنید src/components/contact-form.js و این کد را وارد کنید:

import React, { useState, useContext } from "react";
import { Segment, Form, Input, Button } from "semantic-ui-react";
import _ from "lodash";
import { ContactContext } from "../context/contact-context";

export default function ContactForm() {
  const name = useFormInput("");
  const email = useFormInput("");
  
  const [state, dispatch] = useContext(ContactContext);

  const onSubmit = () => {
    dispatch({
      type: "ADD_CONTACT",
      payload: { id: _.uniqueId(10), name: name.value, email: email.value }
    });
    
    name.onReset();
    email.onReset();
  };

  return (
    <Segment basic>
      <Form onSubmit={onSubmit}>
        <Form.Group widths="3">
          <Form.Field width={6}>
            <Input placeholder="Enter Name" {...name} required />
          </Form.Field>
          <Form.Field width={6}>
            <Input placeholder="Enter Email" {...email} type="email" required />
          </Form.Field>
          <Form.Field width={4}>
            <Button fluid primary>
              New Contact
            </Button>
          </Form.Field>
        </Form.Group>
      </Form>
    </Segment>
  );
}

function useFormInput(initialValue) {
  const [value, setValue] = useState(initialValue);

  const handleChange = e => {
    setValue(e.target.value);
  };

  const handleReset = () => {
    setValue("");
  };

  return {
    value,
    onChange: handleChange,
    onReset: handleReset
  };
}

کد زیر را وارد کنید App.js بر این اساس:

import React from "react";
import { Container } from "semantic-ui-react";
import ContactView from "./views/contact-view";

export default function App() {
  return (
    <Container>
      <h1>React Hooks Context Demo</h1>
    <ContactView />
    </Container>
  );
}

پس از اجرای کد ، صفحه مرورگر شما باید تازه شود. برای حذف مخاطب ، ابتدا باید یک ردیف انتخاب کنید و سپس آن را بزنید حذف دکمه. برای ایجاد یک مخاطب جدید ، به سادگی فرم را پر کرده و آن را بزنید جدید دکمه تماس

همچنین می توانید این کد را روی CodePen تست کنید.

قلم را ببینید
React Hooks Context Demo – لیست تماس
توسط SitePoint (SitePoint)
بر CodePen.

کد را مرور کنید تا مطمئن شوید همه چیز را می فهمید. نظراتی را که در داخل کد آورده ام بخوانید.

خلاصه

امیدوارم که این مثالها به شما کمک کنند تا بتوانید درک کنید که چگونه می توانید حالت برنامه مشترک را در یک برنامه React بدون Redux مدیریت کنید. اگر بخواهید این نمونه ها را بدون قلاب و API زمینه بازنویسی کنید ، کد شما بسیار بیشتر می شد. ببینید نوشتن کد بدون پرداختن به وسایل جانبی چقدر آسان است؟

ممکن است در مثال دوم متوجه شده باشید که چند متغیر حالت بلااستفاده وجود دارد – loading و error. به عنوان یک چالش ، می توانید برای استفاده از آنها ، این برنامه را بیشتر پیشرفت دهید. به عنوان مثال ، می توانید یک تاخیر ساختگی اجرا کنید و باعث شوید که اجزای نمایش وضعیت بارگیری را نشان دهند. همچنین می توانید خیلی بیشتر پیش بروید و به یک API از راه دور واقعی دسترسی پیدا کنید. این جایی است که error متغیر state می تواند در نمایش پیام های خطا مفید باشد.

تنها سوالی که ممکن است اکنون بخواهید از خود بپرسید: آیا Redux برای پروژه های آینده ضروری است؟ یک نقطه ضعف که من با این روش دیده ام این است که شما نمی توانید از آن استفاده کنید پسوند Redux DevTool برای رفع اشکال در حالت برنامه خود. با این حال ، این ممکن است در آینده با توسعه یک ابزار جدید تغییر کند. بدیهی است که به عنوان یک توسعه دهنده ، برای حفظ پروژه های قدیمی همچنان باید Redux را یاد بگیرید. اما اگر پروژه جدیدی را شروع می کنید ، باید از خود و تیم خود بپرسید که آیا استفاده از کتابخانه مدیریت ایالت شخص ثالث برای پرونده شما ضروری است.