From 6d64ee87047192b788b6da79b7cabe362993a5c5 Mon Sep 17 00:00:00 2001 From: Yashgabani845 Date: Sat, 1 Jun 2024 14:52:37 +0530 Subject: [PATCH 1/2] redux-toolkit tutorial added --- .../redux-toolkit/_category_.json | 9 + .../advanced-level/redux-toolkit/lesson_1.md | 154 ++++++++++++++ .../advanced-level/redux-toolkit/lesson_2.md | 173 +++++++++++++++ .../advanced-level/redux-toolkit/lesson_3.md | 197 ++++++++++++++++++ 4 files changed, 533 insertions(+) create mode 100644 courses/react-js/advanced-level/redux-toolkit/_category_.json create mode 100644 courses/react-js/advanced-level/redux-toolkit/lesson_1.md create mode 100644 courses/react-js/advanced-level/redux-toolkit/lesson_2.md create mode 100644 courses/react-js/advanced-level/redux-toolkit/lesson_3.md diff --git a/courses/react-js/advanced-level/redux-toolkit/_category_.json b/courses/react-js/advanced-level/redux-toolkit/_category_.json new file mode 100644 index 000000000..0b40d1453 --- /dev/null +++ b/courses/react-js/advanced-level/redux-toolkit/_category_.json @@ -0,0 +1,9 @@ +{ + "label": "Module 16: Redux Toolkit", + "position": 6, + "link": { + "type": "generated-index", + "description": "In this module, you will learn how to create a new module using the Reduc Toolkit library and create a new module using the new module syntax and about Utilities" + } + } + \ No newline at end of file diff --git a/courses/react-js/advanced-level/redux-toolkit/lesson_1.md b/courses/react-js/advanced-level/redux-toolkit/lesson_1.md new file mode 100644 index 000000000..4c13932f9 --- /dev/null +++ b/courses/react-js/advanced-level/redux-toolkit/lesson_1.md @@ -0,0 +1,154 @@ +--- +id: lesson-1 +title: "Introduction to Redux Toolkit" +sidebar_label: Lesson - 1 +sidebar_position: 1 +description: "In this lesson, you will learn the basics of Redux Toolkit, including its core concepts and how it simplifies the process of managing state in your React applications." +tags: + [ + courses, + redux-toolkit, + react-js, + state-management, + redux, + introduction, + ] +--- + +## Introduction + +Redux Toolkit is the official, recommended way to write Redux logic. It provides a set of tools and best practices that make it easier to write Redux applications. Redux Toolkit includes utilities to simplify common use cases, such as store setup, creating reducers, and writing immutable update logic. + +## Why Use Redux Toolkit? + +Redux Toolkit addresses many common concerns when working with Redux: + +1. **Boilerplate Reduction:** Simplifies the process of creating reducers, actions, and the store. +2. **Immutability:** Enforces immutable state updates using Immer. +3. **Efficiency:** Includes performance optimizations and simplifies common tasks. +4. **Configuration:** Provides built-in middleware like Redux Thunk for handling side effects. + +## Getting Started with Redux Toolkit + +### 1. Installing Redux Toolkit + +To get started with Redux Toolkit, you need to install it along with React-Redux: + +```bash +npm install @reduxjs/toolkit react-redux +``` + +### 2. Creating a Redux Store + +Redux Toolkit provides a `configureStore` function that simplifies store creation. It includes good defaults and automatically sets up the Redux DevTools extension. + +```javascript +// src/app/store.js +import { configureStore } from '@reduxjs/toolkit'; +import counterReducer from '../features/counter/counterSlice'; + +const store = configureStore({ + reducer: { + counter: counterReducer, + }, +}); + +export default store; +``` + +### 3. Creating a Slice + +A slice is a collection of Redux reducer logic and actions for a single feature of your app. Redux Toolkit’s `createSlice` function automatically generates action creators and action types. + +```javascript +// src/features/counter/counterSlice.js +import { createSlice } from '@reduxjs/toolkit'; + +export const counterSlice = createSlice({ + name: 'counter', + initialState: { + value: 0, + }, + reducers: { + increment: (state) => { + state.value += 1; + }, + decrement: (state) => { + state.value -= 1; + }, + incrementByAmount: (state, action) => { + state.value += action.payload; + }, + }, +}); + +export const { increment, decrement, incrementByAmount } = counterSlice.actions; +export default counterSlice.reducer; +``` + +### 4. Using the Redux Store in a React Component + +Now that the store and slice are set up, you can use them in your React components. Use the `useSelector` hook to read state and the `useDispatch` hook to dispatch actions. + +```javascript +// src/features/counter/Counter.js +import React from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { increment, decrement, incrementByAmount } from './counterSlice'; + +function Counter() { + const count = useSelector((state) => state.counter.value); + const dispatch = useDispatch(); + + return ( +
+
+ + {count} + +
+
+ +
+
+ ); +} + +export default Counter; +``` + +### 5. Providing the Redux Store to Your Application + +To make the Redux store available to your entire app, wrap your application in the `Provider` component from `react-redux`. + +```javascript +// src/index.js +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Provider } from 'react-redux'; +import store from './app/store'; +import App from './App'; + +ReactDOM.render( + + + , + document.getElementById('root') +); +``` + +### Redux Data Flow + +Understanding the data flow in Redux is crucial to effectively managing state in your application. The following diagram illustrates how data moves through a Redux application: + +![Redux Data Flow Diagram](https://redux.js.org/assets/images/ReduxDataFlowDiagram-49fa8c3968371d9ef6f2a1486bd40a26.gif) + +*Description:* This diagram demonstrates the unidirectional data flow in Redux: Actions are dispatched by components, which are then processed by reducers to update the state. The updated state is then passed to the components via the store, closing the loop. + +### Conclusion + +In this lesson, you learned the basics of Redux Toolkit, including how to install it, create a Redux store, define a slice, and use the Redux store in your React components. Redux Toolkit simplifies the process of working with Redux by providing utility functions and sensible defaults. Understanding the data flow in Redux will help you build more efficient and maintainable state management solutions. + +--- + +This structured approach provides a solid foundation for managing state with Redux Toolkit, making your Redux code more concise and maintainable. \ No newline at end of file diff --git a/courses/react-js/advanced-level/redux-toolkit/lesson_2.md b/courses/react-js/advanced-level/redux-toolkit/lesson_2.md new file mode 100644 index 000000000..9f217cdb9 --- /dev/null +++ b/courses/react-js/advanced-level/redux-toolkit/lesson_2.md @@ -0,0 +1,173 @@ +--- +id: lesson-2 +title: "Advanced State Management with Redux Toolkit" +sidebar_label: Lesson - 2 +sidebar_position: 2 +description: "In this lesson, you will learn advanced state management techniques using Redux Toolkit, including handling asynchronous actions with createAsyncThunk and managing complex state logic." +tags: + [ + courses, + redux-toolkit, + react-js, + state-management, + redux, + advanced, + ] +--- + +## Introduction + +Creating an API utility for your application is an essential step to manage and separate concerns effectively. By centralizing your API calls, you simplify the process of managing data retrieval, error handling, and side effects, resulting in cleaner and more maintainable code. This lesson will guide you through creating an API utility and using it with Redux Toolkit to manage state in a structured and efficient way. + +## Steps to Create an API Utility + +### 1. Creating an API Utility + +You'll often want to separate your API calls into a dedicated utility file. This approach allows you to centralize the logic for making HTTP requests, making your code more modular and easier to maintain. + +```javascript +// src/features/posts/postsAPI.js +import axios from 'axios'; + +export const fetchPosts = () => { + return axios.get('https://jsonplaceholder.typicode.com/posts'); +}; +``` + +*Description:* The above code creates an API utility using Axios to fetch posts from a placeholder API. This utility function can be reused across different parts of your application wherever you need to fetch posts data. + +### 2. Using Thunks in a Component + +With the API utility created, you can now use it in your Redux slices to handle asynchronous actions. Redux Toolkit provides `createAsyncThunk` to simplify this process. + +```javascript +// src/features/posts/Posts.js +import React, { useEffect } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { fetchPostsAsync } from './postsSlice'; + +function Posts() { + const dispatch = useDispatch(); + const posts = useSelector((state) => state.posts.items); + const status = useSelector((state) => state.posts.status); + const error = useSelector((state) => state.posts.error); + + useEffect(() => { + if (status === 'idle') { + dispatch(fetchPostsAsync()); + } + }, [status, dispatch]); + + return ( +
+ {status === 'loading' &&
Loading...
} + {status === 'succeeded' && ( + + )} + {status === 'failed' &&
{error}
} +
+ ); +} + +export default Posts; +``` + +*Description:* This component uses the `fetchPostsAsync` thunk to fetch posts data when the component mounts. It leverages the Redux state to manage loading, success, and error states, providing a responsive user experience. + +![Redux Toolkit Thunks](https://i.ytimg.com/vi/e0pw9j4pi2A/maxresdefault.jpg) + +*Description:* The image above provides a visual representation of how Redux Toolkit thunks can be used to manage asynchronous operations in your Redux state management. + +## Managing Complex State Logic + +For complex applications, it's important to structure your state effectively to avoid deeply nested structures. Normalizing state makes it easier to update and manage, reducing the likelihood of bugs and improving performance. + +### 1. Normalizing State Structure + +```javascript +// src/features/entities/entitiesSlice.js +import { createSlice } from '@reduxjs/toolkit'; + +const entitiesSlice = createSlice({ + name: 'entities', + initialState: { + users: {}, + posts: {}, + comments: {}, + }, + reducers: { + addUser: (state, action) => { + const user = action.payload; + state.users[user.id] = user; + }, + addPost: (state, action) => { + const post = action.payload; + state.posts[post.id] = post; + }, + addComment: (state, action) => { + const comment = action.payload; + state.comments[comment.id] = comment; + }, + }, +}); + +export const { addUser, addPost, addComment } = entitiesSlice.actions; +export default entitiesSlice.reducer; +``` + +*Description:* This slice normalizes the state structure by storing users, posts, and comments in separate dictionaries indexed by their IDs. This approach allows for efficient state updates and access. + +### 2. Using Entity Adapter + +Redux Toolkit provides `createEntityAdapter` to manage normalized state more efficiently. It includes helpers for common operations like adding, updating, and removing entities. + +```javascript +// src/features/posts/postsSlice.js +import { createSlice, createEntityAdapter } from '@reduxjs/toolkit'; +import { fetchPosts } from './postsAPI'; + +const postsAdapter = createEntityAdapter(); + +const postsSlice = createSlice({ + name: 'posts', + initialState: postsAdapter.getInitialState({ + status: 'idle', + error: null, + }), + reducers: {}, + extraReducers: (builder) => { + builder + .addCase(fetchPosts.pending, (state) => { + state.status = 'loading'; + }) + .addCase(fetchPosts.fulfilled, (state, action) => { + state.status = 'succeeded'; + postsAdapter.setAll(state, action.payload); + }) + .addCase(fetchPosts.rejected, (state, action) => { + state.status = 'failed'; + state.error = action.error.message; + }); + }, +}); + +export const { selectAll: selectAllPosts } = postsAdapter.getSelectors( + (state) => state.posts +); + +export default postsSlice.reducer; +``` + +*Description:* The `postsAdapter` provides a set of pre-built reducers and selectors to manage the posts state. This approach simplifies the implementation of common CRUD operations and ensures consistent state structure. + +## Conclusion + +In this lesson, you learned how to create an API utility and integrate it with Redux Toolkit to manage asynchronous actions. You also explored advanced state management techniques, including normalizing state structures and using entity adapters for efficient state updates. By following these practices, you can build more robust and maintainable Redux applications. + +--- + +This approach to advanced state management with Redux Toolkit ensures your application remains scalable and maintainable as it grows in complexity. \ No newline at end of file diff --git a/courses/react-js/advanced-level/redux-toolkit/lesson_3.md b/courses/react-js/advanced-level/redux-toolkit/lesson_3.md new file mode 100644 index 000000000..f347084a4 --- /dev/null +++ b/courses/react-js/advanced-level/redux-toolkit/lesson_3.md @@ -0,0 +1,197 @@ +--- +id: lesson-3 +title: "Middleware and Custom Redux Logic with Redux Toolkit" +sidebar_label: Lesson - 3 +sidebar_position: 3 +description: "In this lesson, you will learn how to extend Redux functionality with custom middleware and how to write reusable logic with createSlice and createReducer in Redux Toolkit." +tags: + [ + courses, + redux-toolkit, + react-js, + state-management, + redux, + middleware, + custom-logic, + ] +--- + +## Introduction + +In the previous lessons, we covered the basics of Redux Toolkit and advanced state management techniques. In this lesson, we'll explore how to extend Redux functionality with custom middleware and how to write reusable logic using `createSlice` and `createReducer`. + +## Understanding Middleware + +Middleware in Redux is a powerful way to extend the functionality of the store. Middleware can intercept actions before they reach the reducers, allowing you to perform side effects, log actions, or even modify actions. + +### 1. Applying Middleware + +Redux Toolkit's `configureStore` makes it easy to add middleware to your Redux store. + +```javascript +// src/app/store.js +import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'; +import counterReducer from '../features/counter/counterSlice'; +import logger from 'redux-logger'; + +const store = configureStore({ + reducer: { + counter: counterReducer, + }, + middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger), +}); + +export default store; +``` + +### 2. Writing Custom Middleware + +You can write your own custom middleware to handle specific tasks. Middleware is a function that returns another function, which receives the `next` function and the `action`. + +```javascript +// src/middleware/customMiddleware.js +const customMiddleware = (storeAPI) => (next) => (action) => { + console.log('Dispatching action:', action); + let result = next(action); + console.log('Next state:', storeAPI.getState()); + return result; +}; + +export default customMiddleware; +``` + +### 3. Using Custom Middleware + +Add the custom middleware to your Redux store using `configureStore`. + +```javascript +// src/app/store.js +import { configureStore } from '@reduxjs/toolkit'; +import counterReducer from '../features/counter/counterSlice'; +import customMiddleware from '../middleware/customMiddleware'; + +const store = configureStore({ + reducer: { + counter: counterReducer, + }, + middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(customMiddleware), +}); + +export default store; +``` + +## Writing Reusable Logic with createSlice and createReducer + +### 1. Creating a Reusable Slice + +Sometimes you may want to reuse the same logic in different parts of your application. You can create a reusable slice that can be configured for different use cases. + +```javascript +// src/features/toggle/toggleSlice.js +import { createSlice } from '@reduxjs/toolkit'; + +const createToggleSlice = (name) => { + return createSlice({ + name, + initialState: false, + reducers: { + toggle: (state) => !state, + set: (state, action) => action.payload, + }, + }); +}; + +export default createToggleSlice; +``` + +### 2. Using the Reusable Slice + +You can create instances of the reusable slice for different parts of your state. + +```javascript +// src/features/toggle/toggleInstances.js +import createToggleSlice from './toggleSlice'; + +export const lightSlice = createToggleSlice('light'); +export const darkSlice = createToggleSlice('dark'); + +export const { toggle: toggleLight, set: setLight } = lightSlice.actions; +export const { toggle: toggleDark, set: setDark } = darkSlice.actions; + +export default { + light: lightSlice.reducer, + dark: darkSlice.reducer, +}; +``` + +### 3. Combining Reducers + +Use Redux Toolkit's `combineReducers` to combine the reducers into a single reducer. + +```javascript +// src/app/rootReducer.js +import { combineReducers } from '@reduxjs/toolkit'; +import toggleReducers from '../features/toggle/toggleInstances'; + +const rootReducer = combineReducers({ + ...toggleReducers, +}); + +export default rootReducer; +``` + +### 4. Creating the Store + +Create the store with the combined reducer. + +```javascript +// src/app/store.js +import { configureStore } from '@reduxjs/toolkit'; +import rootReducer from './rootReducer'; + +const store = configureStore({ + reducer: rootReducer, +}); + +export default store; +``` + +### 5. Using the Toggle in Components + +Use the toggle slices in your components. + +```javascript +// src/features/toggle/LightSwitch.js +import React from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { toggleLight } from './toggleInstances'; + +function LightSwitch() { + const isLightOn = useSelector((state) => state.light); + const dispatch = useDispatch(); + + return ( +
+ +
+ ); +} + +export default LightSwitch; +``` + +### Conclusion + +In this lesson, you learned how to extend Redux functionality with custom middleware and how to write reusable logic using `createSlice` and `createReducer`. Middleware allows you to intercept and handle actions, while reusable slices enable you to define logic once and use it across multiple parts of your application. + +By mastering these advanced techniques, you can create more powerful and maintainable Redux applications. + +--- + +These three lessons cover the essential aspects of Redux Toolkit, from basic setup to advanced usage and middleware. Each lesson builds on the previous one, providing a comprehensive understanding of how to use Redux Toolkit effectively in your React applications. + +![Middleware and Custom Redux Logic](https://miro.medium.com/v2/resize:fit:724/1*UgcaQCIPE0XGsVkP24yShg.png) + +*Description:* Middleware and custom Redux logic play a crucial role in extending Redux functionality and writing reusable logic. The image above illustrates the concept of middleware in Redux and how it intercepts actions before they reach the reducers, allowing for additional processing or side effects. \ No newline at end of file From 8ec3c1ff1cd24721e8a640c6741f1d4e0ed98c43 Mon Sep 17 00:00:00 2001 From: Yashgabani845 Date: Sat, 1 Jun 2024 15:36:54 +0530 Subject: [PATCH 2/2] all style changed --- .../advanced-level/redux-toolkit/lesson_1.md | 12 ++++------ .../advanced-level/redux-toolkit/lesson_2.md | 12 ++++------ .../advanced-level/redux-toolkit/lesson_3.md | 23 +++++++------------ 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/courses/react-js/advanced-level/redux-toolkit/lesson_1.md b/courses/react-js/advanced-level/redux-toolkit/lesson_1.md index 4c13932f9..206940d7e 100644 --- a/courses/react-js/advanced-level/redux-toolkit/lesson_1.md +++ b/courses/react-js/advanced-level/redux-toolkit/lesson_1.md @@ -42,8 +42,7 @@ npm install @reduxjs/toolkit react-redux Redux Toolkit provides a `configureStore` function that simplifies store creation. It includes good defaults and automatically sets up the Redux DevTools extension. -```javascript -// src/app/store.js +```Javascript title="src/app/store.js" import { configureStore } from '@reduxjs/toolkit'; import counterReducer from '../features/counter/counterSlice'; @@ -60,8 +59,7 @@ export default store; A slice is a collection of Redux reducer logic and actions for a single feature of your app. Redux Toolkit’s `createSlice` function automatically generates action creators and action types. -```javascript -// src/features/counter/counterSlice.js +```javascript title = "src/app/app.js" import { createSlice } from '@reduxjs/toolkit'; export const counterSlice = createSlice({ @@ -90,8 +88,7 @@ export default counterSlice.reducer; Now that the store and slice are set up, you can use them in your React components. Use the `useSelector` hook to read state and the `useDispatch` hook to dispatch actions. -```javascript -// src/features/counter/Counter.js +```javascript title = "src/features/counter/counter.js import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { increment, decrement, incrementByAmount } from './counterSlice'; @@ -121,8 +118,7 @@ export default Counter; To make the Redux store available to your entire app, wrap your application in the `Provider` component from `react-redux`. -```javascript -// src/index.js +```javascript title = "src/index.js" import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; diff --git a/courses/react-js/advanced-level/redux-toolkit/lesson_2.md b/courses/react-js/advanced-level/redux-toolkit/lesson_2.md index 9f217cdb9..17be09040 100644 --- a/courses/react-js/advanced-level/redux-toolkit/lesson_2.md +++ b/courses/react-js/advanced-level/redux-toolkit/lesson_2.md @@ -25,8 +25,7 @@ Creating an API utility for your application is an essential step to manage and You'll often want to separate your API calls into a dedicated utility file. This approach allows you to centralize the logic for making HTTP requests, making your code more modular and easier to maintain. -```javascript -// src/features/posts/postsAPI.js +```javascript title = "src/features/posts/postsAPI.js" import axios from 'axios'; export const fetchPosts = () => { @@ -40,8 +39,7 @@ export const fetchPosts = () => { With the API utility created, you can now use it in your Redux slices to handle asynchronous actions. Redux Toolkit provides `createAsyncThunk` to simplify this process. -```javascript -// src/features/posts/Posts.js +```javascript title = "src/features/posts/Posts.js" import React, { useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { fetchPostsAsync } from './postsSlice'; @@ -88,8 +86,7 @@ For complex applications, it's important to structure your state effectively to ### 1. Normalizing State Structure -```javascript -// src/features/entities/entitiesSlice.js +```javascript title = "src/features/entities/entitiesSlice.js" import { createSlice } from '@reduxjs/toolkit'; const entitiesSlice = createSlice({ @@ -125,8 +122,7 @@ export default entitiesSlice.reducer; Redux Toolkit provides `createEntityAdapter` to manage normalized state more efficiently. It includes helpers for common operations like adding, updating, and removing entities. -```javascript -// src/features/posts/postsSlice.js +```javascript title="src/features/posts/postsSlice.js" import { createSlice, createEntityAdapter } from '@reduxjs/toolkit'; import { fetchPosts } from './postsAPI'; diff --git a/courses/react-js/advanced-level/redux-toolkit/lesson_3.md b/courses/react-js/advanced-level/redux-toolkit/lesson_3.md index f347084a4..f630c43df 100644 --- a/courses/react-js/advanced-level/redux-toolkit/lesson_3.md +++ b/courses/react-js/advanced-level/redux-toolkit/lesson_3.md @@ -28,8 +28,7 @@ Middleware in Redux is a powerful way to extend the functionality of the store. Redux Toolkit's `configureStore` makes it easy to add middleware to your Redux store. -```javascript -// src/app/store.js +```javascript title="src/app/store.js" import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'; import counterReducer from '../features/counter/counterSlice'; import logger from 'redux-logger'; @@ -48,8 +47,7 @@ export default store; You can write your own custom middleware to handle specific tasks. Middleware is a function that returns another function, which receives the `next` function and the `action`. -```javascript -// src/middleware/customMiddleware.js +```javascript title="src/middleware/customMiddleware.js" const customMiddleware = (storeAPI) => (next) => (action) => { console.log('Dispatching action:', action); let result = next(action); @@ -64,8 +62,7 @@ export default customMiddleware; Add the custom middleware to your Redux store using `configureStore`. -```javascript -// src/app/store.js +```javascript title="src/app/store.js" import { configureStore } from '@reduxjs/toolkit'; import counterReducer from '../features/counter/counterSlice'; import customMiddleware from '../middleware/customMiddleware'; @@ -86,7 +83,7 @@ export default store; Sometimes you may want to reuse the same logic in different parts of your application. You can create a reusable slice that can be configured for different use cases. -```javascript +```javascript title="src/features/toggle/toggleSlice.js" // src/features/toggle/toggleSlice.js import { createSlice } from '@reduxjs/toolkit'; @@ -108,8 +105,7 @@ export default createToggleSlice; You can create instances of the reusable slice for different parts of your state. -```javascript -// src/features/toggle/toggleInstances.js +```javascript title="src/fratures/toggle/toggleInstace.js" import createToggleSlice from './toggleSlice'; export const lightSlice = createToggleSlice('light'); @@ -128,8 +124,7 @@ export default { Use Redux Toolkit's `combineReducers` to combine the reducers into a single reducer. -```javascript -// src/app/rootReducer.js +```javascript title = "src/app/rootReducer.js" import { combineReducers } from '@reduxjs/toolkit'; import toggleReducers from '../features/toggle/toggleInstances'; @@ -144,8 +139,7 @@ export default rootReducer; Create the store with the combined reducer. -```javascript -// src/app/store.js +```javascript title = "src/app/store.js" import { configureStore } from '@reduxjs/toolkit'; import rootReducer from './rootReducer'; @@ -160,8 +154,7 @@ export default store; Use the toggle slices in your components. -```javascript -// src/features/toggle/LightSwitch.js +```javascript title ="src/toggle/lightSwitch.js" import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { toggleLight } from './toggleInstances';