Հայերեն
English
Русский
Lesson 17: React Components: Props and State
Understanding Props in React
Introduction to Props
Props, short for "properties," serve as a mechanism for passing data from a parent component to its child components in React. This is a fundamental aspect of React's component model, enabling you to create reusable and customizable components.
Key Characteristics of Props:
- Read-only: Props are immutable from the perspective of the component that receives them. A component cannot change its props, but it can call functions passed via props, which might initiate changes elsewhere.
- Data Flow: Props allow for a unidirectional (downward) data flow, from parent to child. This design helps prevent common bugs caused by the unpredictable data flow in more complex architectures.
Using Props in Components
Props make components dynamic and reusable by providing a mechanism to feed data into a component from a parent. This makes the component more flexible and adaptable to different contexts within the application.
Example: Greeting Component
function Greeting({ username }) {
return <h1>Hello, {username}!</h1>;
}
function App() {
return <Greeting username="Alice" />;
}
In this example:
- The
Greeting component receives a username prop and uses it to display a personalized message.
- The
App component acts as the parent and passes the username prop to the Greeting component.
Props for Event Handling
Props are not limited to data; they can also be used to pass down functions, including event handlers, from parent to child components. This allows child components to communicate back to their parents, enabling interaction within the component hierarchy.
Example: User Interaction
function UserProfile({ user, onEdit }) {
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
<button onClick={onEdit}>Edit</button>
</div>
);
}
function App() {
const user = { name: "Alice", email: "alice@example.com" };
const handleEdit = () => {
console.log('Editing user:', user.name);
};
return <UserProfile user={user} onEdit={handleEdit} />;
}
In this setup:
- The
UserProfile component displays user information and includes an "Edit" button.
- The
App parent component defines a function handleEdit that logs a message when called and passes this function as a prop to UserProfile.
- When the button in
UserProfile is clicked, it triggers the handleEdit function defined in App.
Practical Exercise: User Profile Card Component
Objective: Create a UserProfileCard component that displays a user's name, email, and image. It should also have an "Edit" button that triggers an editing mode defined in the parent component.
Steps:
Define the UserProfileCard Component:
function UserProfileCard({ user, onEdit }) {
return (
<div>
<img src={user.imageUrl} alt={`Profile of ${user.name}`} style={{width: '100px', height: '100px'}} />
<h2>{user.name}</h2>
<p>{user.email}</p>
<button onClick={onEdit}>Edit Profile</button>
</div>
);
}
Use UserProfileCard in a Parent Component:
function App() {
const user = {
name: "Alice Wonderland",
email: "alice@example.com",
imageUrl: "http://example.com/alice.jpg"
};
const handleEdit = () => {
// Implementation for toggling edit mode could go here
console.log("Edit mode activated");
};
return <UserProfileCard user={user} onEdit={handleEdit} />;
}
Exercise Deliverables:
- Students should implement both the
UserProfileCard and the App components.
- They should test passing different user data and functions to
UserProfileCard to ensure it renders correctly and the "Edit" button functions as expected.
This exercise will help students understand the power and flexibility of props in React, enabling them to build interactive and dynamic components that respond to user actions and display data effectively.
Managing State with useState in React
Introduction to State
In React, state refers to a set of data that determines the behavior of a component and how it renders. Unlike props, which are passed from a parent component, state is managed within the component itself. It's mutable and can be initialized and updated based on user actions or other factors.
State plays a crucial role in making components dynamic and interactive. For example, a form input's current value is typically held in state, or a toggle button might track whether it's on or off using state.
Using useState Hook
Introduced in React 16.8, the useState hook allows functional components to have their own state, previously only possible in class components. It's a fundamental hook, essential for adding state management capabilities to functional components.
Syntax and Usage:
useState is a function that takes the initial state as an argument and returns an array containing the current state and a function to update it.
- The pattern
[state, setState] = useState(initialState) is used to declare state in functional components.
Example:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // Initialize the state
const increment = () => {
setCount(count + 1); // Update the state
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
In this example:
count is the state variable that holds the current value of the counter.
setCount is the function used to update count.
- Clicking the "Increment" button triggers
increment, which calls setCount to increase count by 1.
State and Rendering
React components automatically re-render whenever their state changes. This is crucial for keeping the UI up to date with the latest data. React's re-rendering is optimized to be efficient, updating only the parts of the component tree that changed.
Key Concepts:
Hands-On Exercise: Enhancing the UserProfileCard
Objective: Enhance the UserProfileCard component to include editable user details. Implement state to manage the edit mode and form values.
Steps:
Setup Initial State:
function UserProfileCard({ user }) {
const [editMode, setEditMode] = useState(false);
const [formData, setFormData] = useState({ name: user.name, email: user.email });
const handleEdit = () => setEditMode(true);
const handleSave = () => {
// Save the data to some API or state
console.log('Data saved', formData);
setEditMode(false);
};
const handleChange = (e) => setFormData({ ...formData, [e.target.name]: e.target.value });
return (
<div>
{editMode ? (
<>
<input type="text" name="name" value={formData.name} onChange={handleChange} />
<input type="email" name="email" value={formData.email} onChange={handleChange} />
<button onClick={handleSave}>Save</button>
</>
) : (
<>
<h2>{user.name}</h2>
<p>{user.email}</p>
<button onClick={handleEdit}>Edit</button>
</>
)}
</div>
);
}
Task for Students:
- Implement the above changes in the
UserProfileCard.
- Add functionality to toggle
editMode and update user data using state.
- Test by making changes in the form and saving them.
This exercise will provide hands-on experience with managing both static and dynamic state in React components, helping students understand how to build interactive and responsive user interfaces.
Combining Props and State
Component Interaction
In React, components often need to interact with each other to create dynamic and responsive applications. The interaction between components primarily happens through two mechanisms: props and state. While state is used to manage dynamic data within a component, props are used to pass data and event handlers down to child components. This setup allows for efficient data management and component communication in a predictable and structured manner.
Example of Component Interaction:
- A parent component manages a list of tasks as its state.
- Each task from the list is passed to a child component to be rendered. This child component receives the task details as props and may also receive functions as props that allow it to interact with the parent component's state (e.g., to delete a task).
Example Code:
function TaskList() {
const [tasks, setTasks] = useState(['Task 1', 'Task 2', 'Task 3']);
const removeTask = taskIndex => {
const newTasks = tasks.filter((_, index) => index !== taskIndex);
setTasks(newTasks);
};
return (
<div>
{tasks.map((task, index) => (
<TaskItem key={index} task={task} onRemove={() => removeTask(index)} />
))}
</div>
);
}
function TaskItem({ task, onRemove }) {
return (
<div>
<p>{task}</p>
<button onClick={onRemove}>Remove</button>
</div>
);
}
In this setup, the TaskList manages the state of tasks and passes each task to the TaskItem component, along with a function onRemove that can alter the state in TaskList.
State Lifting
State lifting is a common pattern in React development where state is moved up to the closest common ancestor of the components that need access to it. This practice is particularly useful when multiple child components need to interact with the same state.
Benefits of State Lifting:
- Centralized State Management: Managing state at a higher level in the component hierarchy makes it easier to maintain and reason about, especially in larger applications.
- Improved Data Consistency: When state is managed in one location and passed down as props, it ensures that all child components are synchronized and display the same data.
Example Scenario:
- Suppose you have two sibling components that both need to update and display the same data. By lifting the state to their parent component, you ensure both siblings are always in sync.
Practical Application: Small Shopping Cart Application
Objective: Create a shopping cart application where:
- Products are managed in the parent component's state.
- Each product is passed to a child component to display.
- Child components can remove a product from the cart using a handler passed as a prop.
Implementation Steps:
- Parent Component - ShoppingCart:
import React, { useState } from 'react';
import Product from './Product';
function ShoppingCart() {
const [products, setProducts] = useState([
{ id: 1, name: 'Apple', price: '$1' },
{ id: 2, name: 'Banana', price: '$2' }
]);
const handleRemove = productId => {
setProducts(products.filter(product => product.id !== productId));
};
return (
<div>
{products.map(product => (
<Product key={product.id} product={product} onRemove={handleRemove} />
))}
</div>
);
}
- Child Component - Product:
function Product({ product, onRemove }) {
return (
<div>
<h3>{product.name}</h3>
<p>{product.price}</p>
<button onClick={() => onRemove(product.id)}>Remove from Cart</button>
</div>
);
}
Exercise Tasks:
- Students implement the
ShoppingCart and Product components as described.
- Ensure that each product can be removed individually and that the UI updates accordingly when a product is removed.
This exercise helps students understand the practical aspects of managing state in a parent component while using props to allow child components to interact with that state. This approach is foundational for building robust applications with React that require complex interactions between components.
Immutability in State Management
Why Immutability?
Immutability refers to the practice of not changing (mutating) data after it has been created. In the context of React state management, immutability plays a crucial role. React's reactivity model is built around the idea of pure functions and avoiding side effects, which immutability supports. Here are the key benefits:
- Predictability: Immutable state ensures that the state isn't changed unexpectedly elsewhere in the app, leading to more predictable behavior.
- Consistency: With immutable data, every change produces a new object, which helps in maintaining consistency throughout the lifecycle of the application.
- Performance Optimization: React can quickly determine if re-rendering is needed based on changes to the state or props by using shallow comparison. If the reference hasn't changed, React can skip re-rendering.
- Easier Debugging: It's easier to track changes in state over time when each state update produces a new state rather than mutating the existing state. This can be particularly beneficial in complex applications.
Using Spread Operators in State Updates
The spread operator (...) in JavaScript is a useful syntax for making copies of objects or arrays, thus helping to maintain immutability. It allows for the expansion of an iterable (like an array or object) into its individual elements.
Example of Using Spread Operators for Immutability:
Arrays:
When updating an array in the state, you can create a new array with the same elements plus any modifications needed, instead of modifying the original array directly.
const [items, setItems] = useState(['item1', 'item2']);
const addItem = (item) => {
setItems([...items, item]); // Creates a new array with an added item
};
const removeItem = (index) => {
setItems(items.filter((_, i) => i !== index)); // Creates a new array without the specified index
};
Objects:
When modifying properties of an object in the state, the spread operator can be used to create a new object with updated properties.
const [user, setUser] = useState({ name: 'Alice', age: 25 });
const updateUser = (newData) => {
setUser({ ...user, ...newData }); // Creates a new object with updated data
};
Exercise: Update Shopping Cart Quantity
Objective: Enhance the shopping cart application to include functionality for increasing or decreasing the quantity of items in the cart. It's crucial that all state updates adhere to immutability principles.
Steps to Implement:
Update Initial State to Include Quantity:
const [products, setProducts] = useState([
{ id: 1, name: 'Apple', price: '$1', quantity: 2 },
{ id: 2, name: 'Banana', price: '$2', quantity: 3 }
]);
Implement Functions to Modify Quantity:
const incrementQuantity = (productId) => {
setProducts(products.map(product =>
product.id === productId ? { ...product, quantity: product.quantity + 1 } : product
));
};
const decrementQuantity = (productId) => {
setProducts(products.map(product =>
product.id === productId ? { ...product, quantity: product.quantity - 1 } : product
));
};
Integrate Quantity Adjustment into Product Component:
function Product({ product, onRemove, onIncrement, onDecrement }) {
return (
<div>
<h3>{product.name}</h3>
<p>{product.price}</p>
<p>Quantity: {product.quantity}</p>
<button onClick={() => onIncrement(product.id)}>+</button>
<button onClick={() => onDecrement(product.id)}>-</button>
<button onClick={() => onRemove(product.id)}>Remove from Cart</button>
</div>
);
}
Render the Updated Product Component:
Ensure that the ShoppingCart component passes the new functions incrementQuantity and decrementQuantity as props to the Product component.
Task for Students:
- Implement the above changes in the
ShoppingCart and Product components.
- Test the application to ensure that quantity adjustments work correctly and that state updates maintain immutability.
This exercise not only solidifies the students' understanding of state management and immutability but also enhances their ability to implement complex interactions within React applications.
Wrap-up and Q&A
As we conclude today's session on essential React concepts, let's take a moment to review and consolidate the key topics we've discussed. This will help ensure that you have a solid understanding and are prepared to apply these concepts to your own projects.
Review and Summary
1. Understanding Props:
- We explored props (short for "properties"), which are how components receive data from their parent components. Props are crucial for component configuration and ensuring components can be reusable and modular. They are read-only within the component that receives them, which helps in maintaining predictable data flow and behavior.
2. Managing State with useState:
- We delved into managing state within components using the
useState hook, a staple for functional components in React. State allows components to maintain dynamic information that changes over time, enabling them to be interactive (e.g., input fields, toggling UI elements).
- We also covered how state updates trigger component re-renders, facilitating updates to the user interface in response to user actions or other factors.
3. Combining Props and State:
- We discussed how props and state work together to build robust applications. Props pass static or dynamic data down to child components, while state manages changes within components. Understanding both is essential for creating complex and well-functioning React applications.
4. Immutability in State Management:
- The concept of immutability was highlighted, emphasizing its importance in state management. Using tools and methods like the spread operator ensures that the state is updated in a predictable manner, which enhances performance (due to efficient re-rendering) and simplifies debugging.
5. Practical Exercises:
- Through hands-on exercises, you've implemented these concepts by building components that interact through props and state, such as a user profile card and a shopping cart system. These exercises are designed to give you practical experience and confidence in using React's fundamental features.
Q&A Session
Now, let's move into the Q&A session. This is your opportunity to ask any questions that have arisen during today's lesson. Whether you need clarification on a specific topic, assistance with challenges you encountered during the exercises, or advice on applying these concepts to your projects, now is the time to ask. Consider the following:
- Clarifications: If there's any aspect of props, state, or immutability that's unclear, please ask for more details.
- Best Practices: For those interested in best practices around structuring large React applications or managing complex state interactions, feel free to delve into these topics.
- Project Ideas: Discuss how you might use these concepts in potential project ideas or current work you are undertaking. Understanding how to apply what you've learned today can significantly impact your effectiveness and efficiency as a React developer.
This session aims to ensure you leave with a thorough understanding of today's material, ready to build more interactive and dynamic web applications using React.
Դաս 17. Արձագանքել բաղադրիչներ. Հենակետեր և վիճակ
Հասկանալով Props-ը React-ում
Ներածություն Props
Props-ը, որը կրճատված է «հատկություններ» բառից, ծառայում է որպես React-ում մայր բաղադրիչից տվյալների փոխանցման մեխանիզմ: Սա React-ի բաղադրիչ մոդելի հիմնարար ասպեկտն է, որը հնարավորություն է տալիս ստեղծել բազմակի օգտագործման և կարգավորելի բաղադրիչներ:
Հենարանների հիմնական բնութագրերը.
- Միայն կարդալու համար. Հենակետերն անփոփոխ են դրանք ստացող բաղադրիչի տեսանկյունից: Բաղադրիչը չի կարող փոխել իր հենակետերը, բայց այն կարող է կանչել գործառույթներ, որոնք փոխանցվում են հենակետերի միջոցով, ինչը կարող է փոփոխություններ նախաձեռնել այլ վայրերում:
- Տվյալների հոսք. հենարանները թույլ են տալիս միակողմանի (ներքև) տվյալների հոսք՝ ծնողից երեխա: Այս դիզայնը օգնում է կանխել սովորական սխալները, որոնք առաջանում են տվյալների անկանխատեսելի հոսքի պատճառով ավելի բարդ ճարտարապետություններում:
Հենակետերի օգտագործումը բաղադրիչներում
Հենակետերը բաղադրիչները դարձնում են դինամիկ և վերօգտագործելի՝ ապահովելով ծնողից ստացված բաղադրիչի տվյալները փոխանցելու մեխանիզմ: Սա բաղադրիչն ավելի ճկուն և հարմարվող է դարձնում հավելվածի տարբեր համատեքստերին:
Օրինակ՝ ողջույնի բաղադրիչ
function Greeting({ username }) {
return <h1>Hello, {username}!</h1>;
}
function App() {
return <Greeting username="Alice" />;
}
Այս օրինակում.
- Բաղադրիչը
Greetingստանում է usernameհենարան և օգտագործում այն ​​անհատականացված հաղորդագրություն ցուցադրելու համար:
- Բաղադրիչը
Appգործում է որպես ծնող և փոխանցում է usernameհենարանը բաղադրիչին Greeting:
Միջոցառումների սպասարկման պարագաներ
Հենակետերը չեն սահմանափակվում միայն տվյալներով. դրանք կարող են օգտագործվել նաև գործառույթները, ներառյալ իրադարձությունների մշակողները, ծնողներից երեխայի բաղադրիչներին փոխանցելու համար: Սա թույլ է տալիս երեխայի բաղադրիչներին հաղորդակցվել իրենց ծնողների հետ՝ հնարավորություն տալով փոխազդեցություն բաղադրիչի հիերարխիայում:
Օրինակ՝ Օգտագործողի փոխազդեցություն
function UserProfile({ user, onEdit }) {
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
<button onClick={onEdit}>Edit</button>
</div>
);
}
function App() {
const user = { name: "Alice", email: "alice@example.com" };
const handleEdit = () => {
console.log('Editing user:', user.name);
};
return <UserProfile user={user} onEdit={handleEdit} />;
}
Այս կարգավորումներում.
- Բաղադրիչը
UserProfileցուցադրում է օգտվողի տեղեկությունները և ներառում է «Խմբագրել» կոճակը:
- Մայր
Appբաղադրիչը սահմանում է ֆունկցիա handleEdit, որը գրանցում է հաղորդագրությունը, երբ կանչվում է և փոխանցում է այս ֆունկցիան որպես հենակետ UserProfile:
- Երբ կոճակը
UserProfileսեղմվում է, այն գործարկում է handleEditգործառույթը, որը սահմանված է App.
Գործնական վարժություն. Օգտվողի պրոֆիլի քարտի բաղադրիչ
Նպատակը. Ստեղծեք UserProfileCardբաղադրիչ, որը ցուցադրում է օգտվողի անունը, էլ.փոստը և պատկերը: Այն պետք է ունենա նաև «Խմբագրել» կոճակը, որը գործարկում է խմբագրման ռեժիմը, որը սահմանված է մայր բաղադրիչում:
Քայլեր:
Սահմանեք UserProfileCard բաղադրիչը.
function UserProfileCard({ user, onEdit }) {
return (
<div>
<img src={user.imageUrl} alt={`Profile of ${user.name}`} style={{width: '100px', height: '100px'}} />
<h2>{user.name}</h2>
<p>{user.email}</p>
<button onClick={onEdit}>Edit Profile</button>
</div>
);
}
Օգտագործեք UserProfileCard-ը ծնող բաղադրիչում.
function App() {
const user = {
name: "Alice Wonderland",
email: "alice@example.com",
imageUrl: "http://example.com/alice.jpg"
};
const handleEdit = () => {
// Implementation for toggling edit mode could go here
console.log("Edit mode activated");
};
return <UserProfileCard user={user} onEdit={handleEdit} />;
}
Զորավարժությունների առաքում.
- Ուսանողները պետք է իրականացնեն և՛ բաղադրիչները,
UserProfileCardև՛ Appբաղադրիչները:
- Նրանք պետք է փորձարկեն օգտատիրոջ տարբեր տվյալներ և գործառույթներ փոխանցելը, որպեսզի
UserProfileCardհամոզվեն, որ դրանք ճիշտ են մատուցվում, և «Խմբագրել» կոճակը գործում է այնպես, ինչպես սպասվում էր:
Այս վարժությունը կօգնի ուսանողներին հասկանալ React-ի ռեկորդների ուժն ու ճկունությունը՝ հնարավորություն տալով նրանց ստեղծել ինտերակտիվ և դինամիկ բաղադրիչներ, որոնք արձագանքում են օգտագործողի գործողություններին և արդյունավետ կերպով ցուցադրում տվյալները:
Պետության կառավարում UseState-ով React-ում
Ներածություն պետությանը
React-ում վիճակը վերաբերում է տվյալների մի շարքին, որոնք որոշում են բաղադրիչի վարքագիծը և ինչպես է այն ցուցադրվում: Ի տարբերություն հենակետերի, որոնք փոխանցվում են մայր բաղադրիչից, վիճակը կառավարվում է հենց բաղադրիչի ներսում: Այն փոփոխական է և կարող է սկզբնավորվել և թարմացվել՝ ելնելով օգտագործողի գործողություններից կամ այլ գործոններից:
Պետությունը վճռորոշ դեր է խաղում բաղադրիչները դինամիկ և ինտերակտիվ դարձնելու գործում: Օրինակ՝ ձևի մուտքագրման ընթացիկ արժեքը սովորաբար պահվում է վիճակում, կամ փոխարկիչի կոճակը կարող է հետևել՝ արդյոք այն միացված է կամ անջատված՝ օգտագործելով վիճակը:
Օգտագործելով useState Hook-ը
React 16.8-ում ներկայացված useStateկեռիկը թույլ է տալիս ֆունկցիոնալ բաղադրիչներին ունենալ իրենց սեփական վիճակը, որը նախկինում հնարավոր էր միայն դասի բաղադրիչներում: Սա հիմնարար կարթ է, որն անհրաժեշտ է ֆունկցիոնալ բաղադրիչներին պետական ​​կառավարման կարողություններ ավելացնելու համար:
Շարահյուսություն և օգտագործում.
useStateֆունկցիա է, որը սկզբնական վիճակն ընդունում է որպես արգումենտ և վերադարձնում է ընթացիկ վիճակը պարունակող զանգված և այն թարմացնելու ֆունկցիա։
- Կաղապարն
[state, setState] = useState(initialState)օգտագործվում է ֆունկցիոնալ բաղադրիչներում վիճակ հայտարարելու համար:
Օրինակ:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // Initialize the state
const increment = () => {
setCount(count + 1); // Update the state
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
Այս օրինակում.
countվիճակի փոփոխականն է, որը պահում է հաշվիչի ընթացիկ արժեքը:
setCountայն գործառույթն է, որն օգտագործվում է թարմացնելու համար count:
- Սեղմելով «Ավելացում» կոճակը գործարկվում է
increment, որը կոչ է անում setCountավելացնել count1-ով:
Պետություն և մատուցում
React բաղադրիչները ինքնաբերաբար վերարտադրվում են, երբ դրանց վիճակը փոխվում է: Սա շատ կարևոր է միջերեսը վերջին տվյալներին արդի պահելու համար: React-ի վերարտադրումը օպտիմիզացված է արդյունավետ լինելու համար՝ թարմացնելով բաղադրիչի ծառի միայն այն մասերը, որոնք փոխվել են:
Հիմնական հասկացություններ.
Ձեռքի վարժություն. Օգտվողի պրոֆիլի քարտի բարելավում
Նպատակը. Բարելավել UserProfileCardբաղադրիչը՝ ներառելով օգտվողի խմբագրման տվյալները: Իրականացնել վիճակը՝ խմբագրման ռեժիմը և ձևի արժեքները կառավարելու համար:
Քայլեր:
Կարգավորման սկզբնական վիճակը.
function UserProfileCard({ user }) {
const [editMode, setEditMode] = useState(false);
const [formData, setFormData] = useState({ name: user.name, email: user.email });
const handleEdit = () => setEditMode(true);
const handleSave = () => {
// Save the data to some API or state
console.log('Data saved', formData);
setEditMode(false);
};
const handleChange = (e) => setFormData({ ...formData, [e.target.name]: e.target.value });
return (
<div>
{editMode ? (
<>
<input type="text" name="name" value={formData.name} onChange={handleChange} />
<input type="email" name="email" value={formData.email} onChange={handleChange} />
<button onClick={handleSave}>Save</button>
</>
) : (
<>
<h2>{user.name}</h2>
<p>{user.email}</p>
<button onClick={handleEdit}>Edit</button>
</>
)}
</div>
);
}
Առաջադրանք ուսանողների համար.
- Իրականացնել վերը նշված փոփոխությունները
UserProfileCard.
editModeԱվելացրեք գործառույթ ՝ օգտատիրոջ տվյալները փոխելու և թարմացնելու համար՝ օգտագործելով վիճակը:
- Փորձարկեք՝ փոփոխություններ կատարելով ձևի մեջ և պահպանելով դրանք:
Այս վարժությունը գործնական փորձ կապահովի React բաղադրիչներում ստատիկ և դինամիկ վիճակի կառավարման հարցում՝ օգնելով ուսանողներին հասկանալ, թե ինչպես ստեղծել ինտերակտիվ և արձագանքող օգտատիրոջ միջերես:
Հավասարակշռության և վիճակի համադրում
Բաղադրիչների փոխազդեցություն
React-ում բաղադրիչները հաճախ պետք է փոխազդեն միմյանց հետ՝ դինամիկ և արձագանքող հավելվածներ ստեղծելու համար: Բաղադրիչների միջև փոխազդեցությունը հիմնականում տեղի է ունենում երկու մեխանիզմների միջոցով՝ հենարաններ և վիճակ: Մինչ վիճակն օգտագործվում է բաղադրիչի ներսում դինամիկ տվյալները կառավարելու համար, պրոֆիլները օգտագործվում են տվյալների և իրադարձությունների մշակիչները երեխայի բաղադրիչներին փոխանցելու համար: Այս կարգավորումը թույլ է տալիս արդյունավետ կառավարել տվյալների և բաղադրիչների հաղորդակցությունը կանխատեսելի և կառուցվածքային եղանակով:
Բաղադրիչների փոխազդեցության օրինակ.
- Ծնող բաղադրիչը կառավարում է առաջադրանքների ցանկը որպես իր վիճակ:
- Ցանկից յուրաքանչյուր առաջադրանք փոխանցվում է երեխայի բաղադրիչին, որը պետք է ներկայացվի: Այս երեխա բաղադրիչը ստանում է առաջադրանքի մանրամասները որպես հենակետեր և կարող է նաև ստանալ գործառույթներ որպես հենարաններ, որոնք թույլ են տալիս փոխազդել ծնող բաղադրիչի վիճակի հետ (օրինակ՝ ջնջել առաջադրանքը):
Օրինակ Կոդ:
function TaskList() {
const [tasks, setTasks] = useState(['Task 1', 'Task 2', 'Task 3']);
const removeTask = taskIndex => {
const newTasks = tasks.filter((_, index) => index !== taskIndex);
setTasks(newTasks);
};
return (
<div>
{tasks.map((task, index) => (
<TaskItem key={index} task={task} onRemove={() => removeTask(index)} />
))}
</div>
);
}
function TaskItem({ task, onRemove }) {
return (
<div>
<p>{task}</p>
<button onClick={onRemove}>Remove</button>
</div>
);
}
Այս կարգավորումում, TaskListկառավարում է առաջադրանքների վիճակը և յուրաքանչյուր առաջադրանք փոխանցում բաղադրիչին TaskItem, ինչպես նաև մի ֆունկցիա onRemove, որը կարող է փոխել վիճակը TaskList:
Պետական ​​լիֆթինգ
Վիճակի վերացումը սովորական օրինաչափություն է React-ի մշակման մեջ, որտեղ վիճակը տեղափոխվում է դեպի այն բաղադրիչների ամենամոտ ընդհանուր նախահայրը, որոնք մուտքի կարիք ունեն: Այս պրակտիկան հատկապես օգտակար է, երբ մի քանի մանկական բաղադրիչներ պետք է փոխազդեն նույն վիճակի հետ:
Պետական ​​բարձրացման առավելությունները.
- Պետության կենտրոնացված կառավարում. բաղադրամասի հիերարխիայում ավելի բարձր մակարդակի վիճակի կառավարումը հեշտացնում է դրա պահպանումն ու հիմնավորումը, հատկապես ավելի մեծ ծրագրերում:
- Բարելավված տվյալների հետևողականություն. Երբ վիճակը կառավարվում է մեկ վայրում և փոխանցվում որպես հենակետ, այն ապահովում է, որ բոլոր մանկական բաղադրիչները համաժամանակացվեն և ցուցադրեն նույն տվյալները:
Օրինակ սցենար.
- Ենթադրենք, դուք ունեք երկու եղբայր կամ եղբայր բաղադրիչ, որոնք երկուսն էլ պետք է թարմացնեն և ցուցադրեն նույն տվյալները: Բարձրացնելով վիճակը իրենց մայր բաղադրիչին, դուք ապահովում եք, որ երկու եղբայրներն ու եղբայրները միշտ համաժամանակյա են:
Գործնական կիրառություն. Փոքր զամբյուղի հավելված
Նպատակը. Ստեղծեք զամբյուղի հավելված, որտեղ.
- Ապրանքները կառավարվում են մայր բաղադրիչի վիճակում:
- Յուրաքանչյուր ապրանք փոխանցվում է երեխայի բաղադրիչին՝ ցուցադրելու համար:
- Մանկական բաղադրիչները կարող են ապրանքը հեռացնել սայլակից՝ օգտագործելով որպես հենարան փոխանցվող կարգավորիչ:
Իրականացման քայլեր.
- Ծնող բաղադրիչ - Գնումների զամբյուղ.
import React, { useState } from 'react';
import Product from './Product';
function ShoppingCart() {
const [products, setProducts] = useState([
{ id: 1, name: 'Apple', price: '$1' },
{ id: 2, name: 'Banana', price: '$2' }
]);
const handleRemove = productId => {
setProducts(products.filter(product => product.id !== productId));
};
return (
<div>
{products.map(product => (
<Product key={product.id} product={product} onRemove={handleRemove} />
))}
</div>
);
}
- Երեխաների բաղադրիչ - Ապրանք:
function Product({ product, onRemove }) {
return (
<div>
<h3>{product.name}</h3>
<p>{product.price}</p>
<button onClick={() => onRemove(product.id)}>Remove from Cart</button>
</div>
);
}
Զորավարժությունների առաջադրանքներ.
- Ուսանողները կատարում են
ShoppingCartև Productբաղադրիչները, ինչպես նկարագրված է:
- Համոզվեք, որ յուրաքանչյուր ապրանք կարող է առանձին հեռացվել, և որ միջերեսը համապատասխանաբար թարմացվում է, երբ արտադրանքը հեռացվում է:
Այս վարժությունն օգնում է ուսանողներին հասկանալ ծնող բաղադրիչի վիճակը կառավարելու գործնական ասպեկտները՝ միաժամանակ օգտագործելով հենարաններ՝ երեխայի բաղադրիչներին այդ վիճակի հետ փոխազդելու համար: Այս մոտեցումը հիմնարար է React-ի հետ ամուր հավելվածներ ստեղծելու համար, որոնք պահանջում են բաղադրիչների միջև բարդ փոխազդեցություն:
Անփոփոխությունը պետական ​​կառավարման մեջ
Ինչու՞ անփոփոխություն:
Անփոփոխելիությունը վերաբերում է տվյալների ստեղծվելուց հետո չփոխելու (մուտացիայի ենթարկելու) պրակտիկային: React պետական ​​կառավարման համատեքստում անփոփոխությունը վճռորոշ դեր է խաղում: React-ի ռեակտիվության մոդելը կառուցված է մաքուր գործառույթների և կողմնակի ազդեցություններից խուսափելու գաղափարի շուրջ, ինչին աջակցում է անփոփոխությունը: Ահա հիմնական առավելությունները.
- Կանխատեսելիություն. անփոփոխ վիճակն ապահովում է, որ վիճակն անսպասելիորեն չի փոխվի հավելվածում, ինչը հանգեցնում է ավելի կանխատեսելի վարքագծի:
- Հետևողականություն. Անփոփոխ տվյալների դեպքում յուրաքանչյուր փոփոխություն առաջացնում է նոր օբյեկտ, որն օգնում է պահպանել հետևողականությունը հավելվածի կյանքի ցիկլի ընթացքում:
- Արդյունավետության օպտիմիզացում. React-ը կարող է արագ որոշել, թե արդյոք անհրաժեշտ է վերաարտադրել՝ հիմնվելով վիճակի կամ հենակետերի փոփոխությունների վրա՝ օգտագործելով մակերեսային համեմատություն: Եթե ​​հղումը չի փոխվել, React-ը կարող է բաց թողնել վերարտադրումը:
- Ավելի հեշտ վրիպազերծում. ավելի հեշտ է հետևել վիճակի փոփոխություններին ժամանակի ընթացքում, երբ յուրաքանչյուր վիճակի թարմացում ստեղծում է նոր վիճակ, քան գոյություն ունեցող վիճակի փոփոխության: Սա կարող է հատկապես օգտակար լինել բարդ ծրագրերում:
Spread օպերատորների օգտագործումը պետական ​​թարմացումներում
Տարածված օպերատորը ( ...) JavaScript-ում օգտակար շարահյուսություն է՝ օբյեկտների կամ զանգվածների պատճեններ ստեղծելու համար՝ այդպիսով օգնելով պահպանել անփոփոխությունը։ Այն թույլ է տալիս ընդլայնել կրկնվողը (ինչպես զանգվածը կամ առարկան) իր առանձին տարրերի մեջ:
Անփոփոխելիության համար Spread օպերատորների օգտագործման օրինակ.
Զանգվածներ.
վիճակի մեջ զանգվածը թարմացնելիս կարող եք ստեղծել նոր զանգված՝ նույն տարրերով, գումարած անհրաժեշտ փոփոխությունները՝ սկզբնական զանգվածն ուղղակիորեն փոփոխելու փոխարեն:
const [items, setItems] = useState(['item1', 'item2']);
const addItem = (item) => {
setItems([...items, item]); // Creates a new array with an added item
};
const removeItem = (index) => {
setItems(items.filter((_, i) => i !== index)); // Creates a new array without the specified index
};
Օբյեկտներ.
վիճակում գտնվող օբյեկտի հատկությունները փոփոխելիս, տարածման օպերատորը կարող է օգտագործվել նորացված հատկություններով նոր օբյեկտ ստեղծելու համար:
const [user, setUser] = useState({ name: 'Alice', age: 25 });
const updateUser = (newData) => {
setUser({ ...user, ...newData }); // Creates a new object with updated data
};
Զորավարժություն. թարմացնել զամբյուղի քանակը
Նպատակը. Ընդլայնել զամբյուղի հավելվածը՝ ներառելու գործառույթներ զամբյուղում ապրանքների քանակն ավելացնելու կամ նվազեցնելու համար: Շատ կարևոր է, որ բոլոր պետական ​​թարմացումները պահպանվեն անփոփոխելիության սկզբունքներին:
Իրականացման քայլեր.
Թարմացրեք սկզբնական վիճակը՝ քանակն ընդգրկելու համար.
const [products, setProducts] = useState([
{ id: 1, name: 'Apple', price: '$1', quantity: 2 },
{ id: 2, name: 'Banana', price: '$2', quantity: 3 }
]);
Քանակը փոփոխելու գործառույթների իրականացում.
const incrementQuantity = (productId) => {
setProducts(products.map(product =>
product.id === productId ? { ...product, quantity: product.quantity + 1 } : product
));
};
const decrementQuantity = (productId) => {
setProducts(products.map(product =>
product.id === productId ? { ...product, quantity: product.quantity - 1 } : product
));
};
Ինտեգրել քանակի ճշգրտումը արտադրանքի բաղադրիչի մեջ.
function Product({ product, onRemove, onIncrement, onDecrement }) {
return (
<div>
<h3>{product.name}</h3>
<p>{product.price}</p>
<p>Quantity: {product.quantity}</p>
<button onClick={() => onIncrement(product.id)}>+</button>
<button onClick={() => onDecrement(product.id)}>-</button>
<button onClick={() => onRemove(product.id)}>Remove from Cart</button>
</div>
);
}
Արտադրեք թարմացված արտադրանքի բաղադրիչը.
Համոզվեք, որ ShoppingCartբաղադրիչը փոխանցում է նոր գործառույթները incrementQuantityև decrementQuantityորպես օժանդակ բաղադրիչ Product:
Առաջադրանք ուսանողների համար.
- Իրականացնել վերը նշված փոփոխությունները
ShoppingCartև Productբաղադրիչներում:
- Փորձարկեք հավելվածը՝ համոզվելու համար, որ քանակի ճշգրտումները ճիշտ են աշխատում, և որ վիճակի թարմացումները պահպանում են անփոփոխությունը:
Այս վարժությունը ոչ միայն ամրապնդում է ուսանողների ըմբռնումը պետական ​​կառավարման և անփոփոխության մասին, այլև ուժեղացնում է նրանց կարողությունը բարդ փոխազդեցություններ իրականացնելու React հավելվածներում:
Ամփոփում և հարց ու պատասխան
Երբ մենք ավարտում ենք այսօրվա նիստը React-ի հիմնական հասկացությունների վերաբերյալ, եկեք մի պահ տրամադրենք վերանայելու և համախմբելու մեր քննարկած հիմնական թեմաները: Սա կօգնի ապահովել, որ դուք ունեք ամուր պատկերացում և պատրաստ եք կիրառել այս հասկացությունները ձեր սեփական նախագծերում:
Վերանայում և ամփոփում
1. Հասկանալով Props:
- Մենք ուսումնասիրեցինք հենակետերը (կարճ՝ «հատկություններ»), որոնցով բաղադրիչները տվյալներ են ստանում իրենց մայր բաղադրիչներից: Հենակետերը կարևոր են բաղադրիչի կազմաձևման համար և ապահովելու համար, որ բաղադրիչները կարող են կրկնակի օգտագործման և մոդուլային լինել: Դրանք միայն կարդալու են այն բաղադրիչում, որը ստանում է դրանք, ինչը օգնում է կանխատեսելի տվյալների հոսքի և վարքագծի պահպանմանը:
2. Կառավարող պետությունը useState-ով.
- Մենք խորացել ենք բաղադրիչների ներսում վիճակի
useState կառավարման մեջ՝ օգտագործելով կեռիկը, որը React-ի ֆունկցիոնալ բաղադրիչների հիմնական բաղադրիչն է: Պետությունը թույլ է տալիս բաղադրիչներին պահպանել դինամիկ տեղեկատվություն, որը փոխվում է ժամանակի ընթացքում՝ հնարավորություն տալով նրանց լինել ինտերակտիվ (օրինակ՝ մուտքագրման դաշտեր, UI տարրերի փոփոխում):
- Մենք նաև լուսաբանեցինք, թե ինչպես են պետական ​​թարմացումները խթանում բաղադրիչի վերարտադրումը, ինչը հեշտացնում է օգտատիրոջ ինտերֆեյսի թարմացումները՝ ի պատասխան օգտատիրոջ գործողությունների կամ այլ գործոնների:
3. Հավասարակշռության և վիճակի համադրում.
- Մենք քննարկեցինք, թե ինչպես են օժանդակ միջոցները և պետությունը համագործակցում ամուր հավելվածներ ստեղծելու համար: Հենակետերը ստատիկ կամ դինամիկ տվյալներ են փոխանցում երեխայի բաղադրիչներին, մինչդեռ վիճակը կառավարում է բաղադրիչների փոփոխությունները: Երկուսն էլ հասկանալը կարևոր է բարդ և լավ գործող React հավելվածներ ստեղծելու համար:
4. Անփոփոխելիությունը պետական ​​կառավարման մեջ.
- Կարեւորվեց անփոփոխելիության հայեցակարգը ՝ ընդգծելով դրա կարեւորությունը պետական ​​կառավարման գործում։ Գործիքների և մեթոդների օգտագործումը, ինչպիսին է տարածման օպերատորը, ապահովում է, որ վիճակը թարմացվում է կանխատեսելի ձևով, ինչը բարելավում է կատարողականությունը (արդյունավետ վերարտադրման շնորհիվ) և հեշտացնում է վրիպազերծումը:
5. Գործնական վարժություններ.
- Գործնական վարժությունների միջոցով դուք իրականացրել եք այս հասկացությունները՝ կառուցելով բաղադրիչներ, որոնք փոխազդում են հենարանների և վիճակի միջոցով, ինչպիսիք են օգտատիրոջ պրոֆիլի քարտը և գնումների զամբյուղի համակարգը: Այս վարժությունները նախատեսված են ձեզ գործնական փորձ և վստահություն հաղորդելու React-ի հիմնարար հատկանիշները օգտագործելու համար:
Հարց ու պատասխան նիստ
Հիմա եկեք անցնենք հարցուպատասխանի նիստին: Սա ձեր հնարավորությունն է տալ ցանկացած հարց, որը ծագել է այսօրվա դասի ընթացքում: Անկախ նրանից, թե ձեզ պարզաբանումներ են պետք կոնկրետ թեմայի շուրջ, օգնություն՝ զորավարժությունների ընթացքում հանդիպած մարտահրավերների կամ խորհուրդներ՝ ձեր նախագծերում այս հասկացությունները կիրառելու վերաբերյալ, այժմ հարցնելու ժամանակն է: Հաշվի առեք հետևյալը.
- Պարզաբանումներ. Եթե անհասկանալի է հենակետերի, վիճակի կամ անփոփոխելիության որևէ ասպեկտ, խնդրում ենք լրացուցիչ մանրամասների համար հարցնել:
- Լավագույն պրակտիկա. Նրանց համար, ովքեր հետաքրքրված են մեծ React հավելվածների կառուցվածքի կամ բարդ վիճակի փոխազդեցությունների կառավարմամբ լավագույն փորձով, ազատ զգալ խորանալ այս թեմաների մեջ:
- Ծրագրի գաղափարներ. Քննարկեք, թե ինչպես կարող եք օգտագործել այս հասկացությունները պոտենցիալ նախագծի գաղափարներում կամ ընթացիկ աշխատանքում, որը դուք ձեռնարկում եք: Հասկանալը, թե ինչպես կիրառել այն, ինչ սովորել եք այսօր, կարող է էապես ազդել ձեր արդյունավետության և արդյունավետության վրա՝ որպես React ծրագրավորող:
Այս նիստի նպատակն է ապահովել, որ դուք հեռանաք այսօրվա նյութի մանրակրկիտ ըմբռնմամբ, պատրաստ լինելով ստեղծելու ավելի ինտերակտիվ և դինամիկ վեբ հավելվածներ՝ օգտագործելով React:
Урок 17: Компоненты React: реквизиты и состояние
Понимание реквизита в React
Введение в реквизит
Пропсы, сокращение от «свойства», служат механизмом передачи данных от родительского компонента к его дочерним компонентам в React. Это фундаментальный аспект модели компонентов React, позволяющий создавать повторно используемые и настраиваемые компоненты.
Ключевые характеристики реквизита:
- Только для чтения: реквизиты неизменяемы с точки зрения компонента, который их получает. Компонент не может изменять свои свойства, но может вызывать функции, передаваемые через свойства, которые могут инициировать изменения в другом месте.
- Поток данных: реквизиты обеспечивают однонаправленный (нисходящий) поток данных от родительского элемента к дочернему. Такая конструкция помогает предотвратить распространенные ошибки, вызванные непредсказуемым потоком данных в более сложных архитектурах.
Использование реквизитов в компонентах
Реквизиты делают компоненты динамическими и пригодными для повторного использования, предоставляя механизм передачи данных в компонент от родителя. Это делает компонент более гибким и адаптируемым к различным контекстам приложения.
Пример: компонент приветствия
function Greeting({ username }) {
return <h1>Hello, {username}!</h1>;
}
function App() {
return <Greeting username="Alice" />;
}
В этом примере:
- Компонент
Greetingполучает usernameсвойство и использует его для отображения персонализированного сообщения.
- Компонент
Appдействует как родительский и передает usernameсвойство компоненту Greeting.
Реквизит для обработки событий
Реквизит не ограничивается данными; их также можно использовать для передачи функций, включая обработчики событий, от родительских компонентов к дочерним. Это позволяет дочерним компонентам связываться со своими родителями, обеспечивая взаимодействие внутри иерархии компонентов.
Пример: взаимодействие с пользователем
function UserProfile({ user, onEdit }) {
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
<button onClick={onEdit}>Edit</button>
</div>
);
}
function App() {
const user = { name: "Alice", email: "alice@example.com" };
const handleEdit = () => {
console.log('Editing user:', user.name);
};
return <UserProfile user={user} onEdit={handleEdit} />;
}
В этой настройке:
- Компонент
UserProfileотображает информацию о пользователе и включает кнопку «Редактировать».
- Родительский
Appкомпонент определяет функцию handleEdit, которая регистрирует сообщение при вызове и передает эту функцию в качестве свойства UserProfile.
- Когда кнопка нажата
UserProfile, она запускает handleEditфункцию, определенную в App.
Практическое упражнение: компонент карты профиля пользователя
Цель: создать UserProfileCardкомпонент, который отображает имя пользователя, адрес электронной почты и изображение. Он также должен иметь кнопку «Редактировать», которая запускает режим редактирования, определенный в родительском компоненте.
Шаги:
Определите компонент UserProfileCard:
function UserProfileCard({ user, onEdit }) {
return (
<div>
<img src={user.imageUrl} alt={`Profile of ${user.name}`} style={{width: '100px', height: '100px'}} />
<h2>{user.name}</h2>
<p>{user.email}</p>
<button onClick={onEdit}>Edit Profile</button>
</div>
);
}
Используйте UserProfileCard в родительском компоненте:
function App() {
const user = {
name: "Alice Wonderland",
email: "alice@example.com",
imageUrl: "http://example.com/alice.jpg"
};
const handleEdit = () => {
// Implementation for toggling edit mode could go here
console.log("Edit mode activated");
};
return <UserProfileCard user={user} onEdit={handleEdit} />;
}
Результаты упражнения:
- Студенты должны реализовать как компоненты, так
UserProfileCardи Appкомпоненты.
- Им следует протестировать передачу различных пользовательских данных и функций, чтобы
UserProfileCardубедиться, что они отображаются правильно и кнопка «Редактировать» работает должным образом.
Это упражнение поможет учащимся понять мощь и гибкость реквизитов в React, что позволит им создавать интерактивные и динамические компоненты, которые реагируют на действия пользователя и эффективно отображают данные.
Управление состоянием с помощью useState в React
Введение в состояние
В React состояние относится к набору данных, которые определяют поведение компонента и то, как он отображается. В отличие от реквизитов, которые передаются из родительского компонента, состояние управляется внутри самого компонента. Он изменчив и может инициализироваться и обновляться в зависимости от действий пользователя или других факторов.
Состояние играет решающую роль в обеспечении динамичности и интерактивности компонентов. Например, текущее значение ввода формы обычно сохраняется в состоянии, или кнопка-переключатель может отслеживать, включено оно или выключено, используя состояние.
Использование хука useState
Хук , представленный в React 16.8, useStateпозволяет функциональным компонентам иметь собственное состояние, что ранее было возможно только в компонентах классов. Это фундаментальный крючок, необходимый для добавления возможностей управления состоянием к функциональным компонентам.
Синтаксис и использование:
useState— это функция, которая принимает начальное состояние в качестве аргумента и возвращает массив, содержащий текущее состояние, и функцию для его обновления.
- Шаблон
[state, setState] = useState(initialState)используется для объявления состояния в функциональных компонентах.
Пример:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // Initialize the state
const increment = () => {
setCount(count + 1); // Update the state
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
В этом примере:
count— переменная состояния, содержащая текущее значение счетчика.
setCountэто функция, используемая для обновления count.
- При нажатии кнопки «Увеличить» срабатывает
increment, который вызывает setCountувеличение countна 1.
Состояние и рендеринг
Компоненты React автоматически перерисовываются при каждом изменении их состояния. Это крайне важно для поддержания пользовательского интерфейса в актуальном состоянии с учетом последних данных. Повторный рендеринг React оптимизирован для повышения эффективности: обновляются только те части дерева компонентов, которые изменились.
Ключевые идеи:
Практическое упражнение: улучшение UserProfileCard
Цель: усовершенствовать UserProfileCardкомпонент, включив в него редактируемые сведения о пользователе. Реализуйте состояние для управления режимом редактирования и значениями формы.
Шаги:
Начальное состояние настройки:
function UserProfileCard({ user }) {
const [editMode, setEditMode] = useState(false);
const [formData, setFormData] = useState({ name: user.name, email: user.email });
const handleEdit = () => setEditMode(true);
const handleSave = () => {
// Save the data to some API or state
console.log('Data saved', formData);
setEditMode(false);
};
const handleChange = (e) => setFormData({ ...formData, [e.target.name]: e.target.value });
return (
<div>
{editMode ? (
<>
<input type="text" name="name" value={formData.name} onChange={handleChange} />
<input type="email" name="email" value={formData.email} onChange={handleChange} />
<button onClick={handleSave}>Save</button>
</>
) : (
<>
<h2>{user.name}</h2>
<p>{user.email}</p>
<button onClick={handleEdit}>Edit</button>
</>
)}
</div>
);
}
Задание для учеников:
- Внесите вышеуказанные изменения в файл
UserProfileCard.
- Добавьте функциональность для переключения
editModeи обновления пользовательских данных с использованием состояния.
- Протестируйте, внеся изменения в форму и сохранив их.
Это упражнение предоставит практический опыт управления статическим и динамическим состоянием в компонентах React, помогая студентам понять, как создавать интерактивные и адаптивные пользовательские интерфейсы.
Объединение реквизита и состояния
Взаимодействие компонентов
В React компонентам часто необходимо взаимодействовать друг с другом для создания динамичных и отзывчивых приложений. Взаимодействие между компонентами в основном происходит посредством двух механизмов: реквизита и состояния. В то время как состояние используется для управления динамическими данными внутри компонента, реквизиты используются для передачи данных и обработчиков событий дочерним компонентам. Такая настройка обеспечивает эффективное управление данными и взаимодействие компонентов предсказуемым и структурированным образом.
Пример взаимодействия компонентов:
- Родительский компонент управляет списком задач в качестве своего состояния.
- Каждая задача из списка передается дочернему компоненту для визуализации. Этот дочерний компонент получает сведения о задаче в качестве реквизита, а также может получать функции в качестве реквизита, которые позволяют ему взаимодействовать с состоянием родительского компонента (например, удалять задачу).
Пример кода:
function TaskList() {
const [tasks, setTasks] = useState(['Task 1', 'Task 2', 'Task 3']);
const removeTask = taskIndex => {
const newTasks = tasks.filter((_, index) => index !== taskIndex);
setTasks(newTasks);
};
return (
<div>
{tasks.map((task, index) => (
<TaskItem key={index} task={task} onRemove={() => removeTask(index)} />
))}
</div>
);
}
function TaskItem({ task, onRemove }) {
return (
<div>
<p>{task}</p>
<button onClick={onRemove}>Remove</button>
</div>
);
}
В этой настройке TaskListуправляет состоянием задач и передает каждую задачу компоненту TaskItemвместе с функцией onRemove, которая может изменять состояние в TaskList.
Государственный подъем
Поднятие состояния — это распространенный шаблон в разработке React, когда состояние перемещается к ближайшему общему предку компонентов, которым необходим доступ к нему. Эта практика особенно полезна, когда нескольким дочерним компонентам необходимо взаимодействовать с одним и тем же состоянием.
Преимущества государственного подъема:
- Централизованное управление состоянием. Управление состоянием на более высоком уровне в иерархии компонентов упрощает обслуживание и анализ, особенно в более крупных приложениях.
- Улучшенная согласованность данных: когда состояние управляется в одном месте и передается как реквизит, это гарантирует, что все дочерние компоненты синхронизированы и отображают одни и те же данные.
Пример сценария:
- Предположим, у вас есть два родственных компонента, которым необходимо обновлять и отображать одни и те же данные. Передавая состояние их родительскому компоненту, вы гарантируете, что оба родственных компонента всегда синхронизированы.
Практическое применение: небольшая тележка для покупок
Цель: Создать приложение для корзины покупок, в котором:
- Продукты управляются в состоянии родительского компонента.
- Каждый продукт передается дочернему компоненту для отображения.
- Дочерние компоненты могут удалять товар из корзины с помощью обработчика, переданного в качестве реквизита.
Этапы реализации:
- Родительский компонент — ShoppingCart:
import React, { useState } from 'react';
import Product from './Product';
function ShoppingCart() {
const [products, setProducts] = useState([
{ id: 1, name: 'Apple', price: '$1' },
{ id: 2, name: 'Banana', price: '$2' }
]);
const handleRemove = productId => {
setProducts(products.filter(product => product.id !== productId));
};
return (
<div>
{products.map(product => (
<Product key={product.id} product={product} onRemove={handleRemove} />
))}
</div>
);
}
- Дочерний компонент — Продукт:
function Product({ product, onRemove }) {
return (
<div>
<h3>{product.name}</h3>
<p>{product.price}</p>
<button onClick={() => onRemove(product.id)}>Remove from Cart</button>
</div>
);
}
Задачи упражнения:
- Учащиеся реализуют компоненты
ShoppingCartи Product, как описано.
- Убедитесь, что каждый продукт можно удалить по отдельности и что пользовательский интерфейс обновляется соответствующим образом при удалении продукта.
Это упражнение помогает учащимся понять практические аспекты управления состоянием родительского компонента при использовании свойств, позволяющих дочерним компонентам взаимодействовать с этим состоянием. Этот подход является основой для создания надежных приложений с помощью React, требующих сложного взаимодействия между компонентами.
Неизменяемость в управлении состоянием
Почему неизменность?
Неизменяемость означает практику неизменения (мутации) данных после их создания. В контексте управления состоянием React неизменяемость играет решающую роль. Модель реактивности React построена на идее чистых функций и исключении побочных эффектов, которые поддерживает неизменяемость. Вот ключевые преимущества:
- Предсказуемость. Неизменяемое состояние гарантирует, что состояние не изменится неожиданно где-либо в приложении, что приводит к более предсказуемому поведению.
- Согласованность. Благодаря неизменяемым данным каждое изменение создает новый объект, что помогает поддерживать согласованность на протяжении всего жизненного цикла приложения.
- Оптимизация производительности: React может быстро определить, нужен ли повторный рендеринг, на основе изменений состояния или реквизитов, используя поверхностное сравнение. Если ссылка не изменилась, React может пропустить повторный рендеринг.
- Упрощенная отладка. Легче отслеживать изменения состояния с течением времени, когда каждое обновление состояния создает новое состояние, а не изменяет существующее состояние. Это может быть особенно полезно в сложных приложениях.
Использование операторов расширения в обновлениях состояния
Оператор распространения ( ...) в JavaScript — это полезный синтаксис для создания копий объектов или массивов, помогающий поддерживать неизменяемость. Он позволяет расширять итерацию (например, массив или объект) на отдельные элементы.
Пример использования операторов распространения для неизменяемости:
Массивы:
при обновлении массива в состоянии вы можете создать новый массив с теми же элементами и любыми необходимыми изменениями вместо непосредственного изменения исходного массива.
const [items, setItems] = useState(['item1', 'item2']);
const addItem = (item) => {
setItems([...items, item]); // Creates a new array with an added item
};
const removeItem = (index) => {
setItems(items.filter((_, i) => i !== index)); // Creates a new array without the specified index
};
Объекты:
при изменении свойств объекта в состоянии оператор распространения можно использовать для создания нового объекта с обновленными свойствами.
const [user, setUser] = useState({ name: 'Alice', age: 25 });
const updateUser = (newData) => {
setUser({ ...user, ...newData }); // Creates a new object with updated data
};
Упражнение: обновление количества в корзине покупок
Цель: расширить приложение корзины покупок, включив в него функции увеличения или уменьшения количества товаров в корзине. Крайне важно, чтобы все обновления состояния соответствовали принципам неизменности.
Шаги по реализации:
Обновите исходное состояние, чтобы включить количество:
const [products, setProducts] = useState([
{ id: 1, name: 'Apple', price: '$1', quantity: 2 },
{ id: 2, name: 'Banana', price: '$2', quantity: 3 }
]);
Реализация функций для изменения количества:
const incrementQuantity = (productId) => {
setProducts(products.map(product =>
product.id === productId ? { ...product, quantity: product.quantity + 1 } : product
));
};
const decrementQuantity = (productId) => {
setProducts(products.map(product =>
product.id === productId ? { ...product, quantity: product.quantity - 1 } : product
));
};
Интегрируйте корректировку количества в компонент продукта:
function Product({ product, onRemove, onIncrement, onDecrement }) {
return (
<div>
<h3>{product.name}</h3>
<p>{product.price}</p>
<p>Quantity: {product.quantity}</p>
<button onClick={() => onIncrement(product.id)}>+</button>
<button onClick={() => onDecrement(product.id)}>-</button>
<button onClick={() => onRemove(product.id)}>Remove from Cart</button>
</div>
);
}
Отобразите обновленный компонент продукта.
Убедитесь, что ShoppingCartкомпонент передает новые функции incrementQuantityи decrementQuantityреквизиты компоненту Product.
Задание для учеников:
- Внесите вышеуказанные изменения в компоненты
ShoppingCartи Product.
- Протестируйте приложение, чтобы убедиться, что корректировки количества работают правильно и что обновления состояния сохраняют неизменность.
Это упражнение не только укрепляет понимание студентами управления состоянием и неизменяемости, но также расширяет их способность реализовывать сложные взаимодействия в приложениях React.
Подведение итогов и вопросы и ответы
Завершая сегодняшнюю сессию по основным концепциям React, давайте уделим немного времени обзору и обобщению ключевых тем, которые мы обсуждали. Это поможет вам получить четкое понимание и готовность применить эти концепции в своих собственных проектах.
Обзор и резюме
1. Понимание реквизита:
- Мы рассмотрели реквизиты (сокращенно от «свойства»), которые определяют, как компоненты получают данные от своих родительских компонентов. Реквизиты имеют решающее значение для конфигурации компонентов и обеспечения возможности многократного использования и модульности компонентов. Они доступны только для чтения внутри компонента, который их получает, что помогает поддерживать предсказуемый поток и поведение данных.
2. Управление состоянием с помощью useState:
- Мы углубились в управление состоянием компонентов с помощью
useStateхука — основного компонента функциональных компонентов в React. Состояние позволяет компонентам сохранять динамическую информацию, которая меняется со временем, что позволяет им быть интерактивными (например, поля ввода, переключение элементов пользовательского интерфейса).
- Мы также рассмотрели, как обновления состояния вызывают повторную отрисовку компонентов, облегчая обновление пользовательского интерфейса в ответ на действия пользователя или другие факторы.
3. Объединение реквизита и состояния:
- Мы обсудили, как реквизиты и состояние работают вместе для создания надежных приложений. Реквизиты передают статические или динамические данные дочерним компонентам, а состояние управляет изменениями внутри компонентов. Понимание того и другого необходимо для создания сложных и хорошо функционирующих приложений React.
4. Неизменность в управлении состоянием:
- Было выделено понятие неизменяемости , подчеркнуто его значение в государственном управлении. Использование инструментов и методов, таких как оператор распространения, гарантирует, что состояние обновляется предсказуемым образом, что повышает производительность (за счет эффективного повторного рендеринга) и упрощает отладку.
5. Практические упражнения:
- С помощью практических упражнений вы реализовали эти концепции, создав компоненты, которые взаимодействуют через реквизиты и состояние, такие как карточка профиля пользователя и система корзины покупок. Эти упражнения призваны дать вам практический опыт и уверенность в использовании фундаментальных функций React.
Сессия вопросов и ответов
Теперь давайте перейдем к сеансу вопросов и ответов. Это ваша возможность задать любые вопросы, возникшие в ходе сегодняшнего урока. Если вам нужны разъяснения по конкретной теме, помощь в решении проблем, с которыми вы столкнулись во время упражнений, или совет по применению этих концепций в ваших проектах, сейчас самое время спросить. Учтите следующее:
- Пояснения: если какой-либо аспект реквизита, состояния или неизменяемости неясен, запросите дополнительную информацию.
- Лучшие практики. Тем, кто интересуется лучшими практиками структурирования больших приложений React или управления сложными взаимодействиями между состояниями, не стесняйтесь углубляться в эти темы.
- Идеи проекта: обсудите, как вы могли бы использовать эти концепции в потенциальных идеях проекта или текущей работе, которую вы выполняете. Понимание того, как применять то, что вы узнали сегодня, может существенно повлиять на вашу эффективность и результативность как разработчика React.
Целью этого занятия является обеспечение того, чтобы вы закончили с глубоким пониманием сегодняшнего материала и были готовы создавать более интерактивные и динамичные веб-приложения с использованием React.