When building forms in React, sometimes you want one field to copy values from another field — but only if it is still empty. For example, you may want a mediaContentUrl field to auto-fill with the same value a user types in another field.
A common problem is that after the first letter, the mediaContentUrl field is no longer "empty," so it stops updating. The trick is to keep syncing while it matches the other field, and stop once the user edits it directly.
Here’s a simplified fix you can use inside your change handler:
setFormValues(prev => {
const updated = { ...prev, [name]: value, mediaFile: null };
// Only sync if mediaContentUrl is empty
// or still the same as the field being typed
if (name !== "mediaContentUrl") {
const prevField = String(prev[name] ?? "");
const prevMedia = String(prev.mediaContentUrl ?? "");
if (!prevMedia || prevMedia === prevField) {
updated.mediaContentUrl = value;
}
}
return updated;
});
This way, the mediaContentUrl field will auto-fill until the user changes it, and then it stops syncing.
When building tree structures in React, you might see this warning:
"Encountered two children with the same key..."
This usually happens when your component is rendering a list or tree and uses the same key value for multiple items. React requires that keys be unique among siblings to correctly track changes.
In some apps, a tree of items is built using IDs like id, targetId, and parentId. A common mistake is using a field like targetId as the unique key — but if that field isn't truly unique, React throws an error.
Also, when building the tree structure, developers often assume that parentId matches a node’s id, but sometimes it actually matches others like targetId — and since targetId isn't unique, that causes lookup problems.
Here’s how to correctly build the tree and avoid duplicate keys:
id as the unique key — it's meant to be unique and stable.id.targetId to nodes — since targetId isn't unique, store an array of nodes per targetId.parentId to the corresponding targetId, and attach the node to all matches (if multiple).Here’s a simplified version of the corrected tree builder:
function buildTree(nodes) {
const updatedNodes = nodes.map(node => ({
...node,
id: String(node.id),
targetId: String(node.targetId),
parentId: String(node.parentId),
children: [],
}));
const targetIdToNodes = {};
updatedNodes.forEach(node => {
if (!targetIdToNodes[node.targetId]) {
targetIdToNodes[node.targetId] = [];
}
targetIdToNodes[node.targetId].push(node);
});
const rootNodes = [];
updatedNodes.forEach(node => {
if (node.parentId === '0') {
rootNodes.push(node);
} else {
const parents = targetIdToNodes[node.parentId];
if (parents) {
parents.forEach(parent => {
parent.children.push(node);
});
}
}
});
return rootNodes;
}
In your React rendering, always use node.id for the key:
<TreeNode key={node.id} node={node} />
Always make sure your keys in React are unique and stable. And when building a tree, know what your parentId is pointing to — it can make or break your structure.
JSX may look like HTML, but it’s actually JavaScript. When used correctly, it brings power and clarity to React development.
{} for JavaScript expressions.className instead of class.<img />.<div> or <>.Example:
function Greeting() {
return <h1>Hello, world!</h1>;
}
class instead of className.When using ref in React, especially with forwardRef, it's important to understand how ref works — and how it doesn't.
You might see this warning in your console:
refis not a prop. Trying to access it will result inundefinedbeing returned...
This usually happens when you try to declare ref in your component's propTypes or access it like a normal prop (props.ref). But ref is a special prop in React. It doesn't behave like other props.
refWhen using forwardRef, React gives the ref as the second argument of your function. Here's what that looks like:
const MyComponent = forwardRef(function MyComponent(props, ref) {
// use ref directly
});
Don't try to access ref through props.ref. That won't work.
MyComponent.propTypes = {
// This will trigger a warning!
ref: PropTypes.any,
};
React doesn't pass ref through the normal props object, so it shouldn’t be validated with propTypes.
ref only via the second argument in forwardRef.ref from propTypes.This will prevent the warning and adhere to React best practices.
If you're using TinyMCE in a React app and want to provide users with a way to remove all data-* attributes from their content, you can create a custom toolbar button to do just that.
data-* attributes are often added by frameworks, plugins, or tracking tools. In some cases, you might want to remove these before saving or publishing content, especially for clean, production-ready HTML.
You can use TinyMCE’s setup function to add a custom button with a mop-like icon to your toolbar. Here's how:
import { Editor } from '@tinymce/tinymce-react';
function MyEditor({ content, contentChange, onEditorInit }) {
return (
<Editor
value={content}
onEditorChange={(newValue) => contentChange(newValue)}
onInit={onEditorInit}
init={{
height: 500,
menubar: false,
plugins: 'code',
toolbar: 'undo redo | mopCleaner | bold italic underline | code',
setup: (editor) => {
editor.ui.registry.addIcon('mopCleanerIcon', `
<svg width="24" height="24" viewBox="0 0 24 24">
<path d="M12 2v14" stroke="currentColor" stroke-width="2"/>
<path d="M8 16h8l1 4H7l1-4z" fill="currentColor"/>
</svg>
`);
editor.ui.registry.addButton('mopCleaner', {
icon: 'mopCleanerIcon',
tooltip: 'Remove all data-* attributes',
onAction: () => {
const currentContent = editor.getContent();
const cleanedContent = currentContent.replace(/\sdata-[\w-]+="[^"]*"/g, '');
editor.setContent(cleanedContent);
},
});
},
}}
/>
);
}
data-something="value".data-* attributes are in a single tag.To support edge cases, such as attributes with single quotes or no values, you can enhance the regex as needed.
TinyMCE is a popular rich text editor used to add content-editing capabilities to web apps. When working with React, TinyMCE provides an official wrapper that makes integration quick and easy.
Here’s how to set it up in a React project:
Use npm:
npm install @tinymce/tinymce-react
Import the component and render it:
import { Editor } from '@tinymce/tinymce-react';
function MyEditor() {
return (
<Editor
initialValue="<p>Start typing...</p>"
init={{
height: 300,
menubar: false,
plugins: 'link image code',
toolbar: 'undo redo | formatselect | bold italic | link image | code',
}}
/>
);
}
This will render a fully functional rich text editor inside your React component.
You can capture changes to the editor content like this:
<Editor
onEditorChange={(newContent) => {
console.log(newContent); // Save or process the content here
}}
/>
TinyMCE is highly customizable with plugins, themes, and custom toolbars.
You can host TinyMCE locally or use the cloud version.
It supports custom buttons, icons, and content filtering.
Visit TinyMCE React Docs for advanced configuration options.
JavaScript Date objects are always created and manipulated relative to the user’s local timezone, which it gets from the environment.
const date = new Date("2025-05-27T20:03:00Z"); // stored as UTC
console.log(date.toString());
// → "Tue May 27 2025 22:03:00 GMT+0200 (Central European Summer Time)"
To determine the client’s timezone:
Intl.DateTimeFormat().resolvedOptions().timeZone
// → "Europe/Berlin" or similar
This automatic timezone handling is key to understanding how UTC inputs appear offset when viewed or edited on the frontend.
To display datetimes in the user's local timezone while preserving backend UTC storage, you can use JavaScript's built-in timezone offset support:
const utcDate = "2025-05-27T20:03:00Z";
const localDisplay = new Date(utcDate).toLocaleString();
// → "5/27/2025, 10:03 PM" (depending on user's locale)
This gives users a familiar and correctly adjusted view of time. For a consistent format, Intl.DateTimeFormat can be used.
ASP.NET Core with System.Text.Json handles ISO 8601 UTC strings automatically when binding to DateTime properties. Ensure you're not converting to UTC again if the incoming data already ends with Z.
Best Practices:
[JsonPropertyName("created")]
public DateTime Created { get; set; } // Will be parsed as UTC if ends in "Z"
If needed, ensure correct serialization:
private readonly JsonSerializerOptions _jsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Converters = { new UtcDateTimeConverter() }
};
Custom converter (if required):
public class UtcDateTimeConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> DateTime.SpecifyKind(reader.GetDateTime(), DateTimeKind.Utc);
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
=> writer.WriteStringValue(value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ"));
}
When a user selects a datetime in a <input type="datetime-local">, the returned value (e.g., "2025-05-27T22:03") is in local time. To maintain UTC consistency on the backend, this must be converted to UTC.
Implementation:
const handleChange = (e) => {
const local = new Date(e.target.value); // local time
const utc = local.toISOString(); // UTC string for API
setPost({ ...post, created: utc });
};
This ensures accurate time data regardless of the user's timezone.
To populate an <input type="datetime-local"> in React, you must convert your UTC string into a local time string formatted as "yyyy-MM-ddTHH:mm" — the only format the input accepts.
Implementation:
function toDatetimeLocalValue(dateInput) {
const date = new Date(dateInput);
const pad = (n) => n.toString().padStart(2, '0');
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
}
Use this function when binding input values in forms to ensure users see time in their own timezone.
When working with frontend frameworks like React and backend APIs such as ASP.NET Core, ensuring consistent and accurate DateTime handling across timezones is essential — especially when dealing with user input via <input type="datetime-local"> and when storing timestamps like created, modified, and published in UTC in a database.
This Snippset explores a practical and professional strategy for:
Accepting and formatting user input in local time
Converting local times to UTC before sending to the server
Storing and retrieving UTC in ASP.NET Core
Formatting and displaying local time correctly on the frontend
All examples assume the use of modern JSON APIs with ISO 8601 strings ("2025-05-27T20:03:00Z") and an object-based form model in React.
Overview: In many situations, you may need to store more than just simple values in an array. Extending arrays to include attributes such as gender, language, or other metadata can add significant flexibility to your data. This Snipp shows how to structure an array to include such attributes.
Implementation:
const namesWithAttributes = [
{ name: "Norbert", gender: "male", language: "German" },
{ name: "Manuela", gender: "female", language: "Spanish" },
{ name: "Saskia", gender: "female", language: "Dutch" },
{ name: "Henrik", gender: "male", language: "Swedish" },
{ name: "Claus", gender: "male", language: "Danish" },
];
In this example, each item in the array is an object containing a name, gender, and language. This structure allows you to filter and manipulate the data based on multiple attributes easily.
Overview: In some cases, you may want to return only specific fields from filtered data, such as extracting only the name from a list of people. This Snipp demonstrates how to combine filtering and mapping to achieve this.
Implementation:
// Filter by gender and return only names
const maleNames = namesWithAttributes
.filter(person => person.gender === "male")
.map(person => person.name);
console.log(maleNames);
// Output: ["Norbert", "Henrik", "Claus"]
This approach combines the filter() and map() methods to first filter the data by gender and then extract only the name field from the resulting objects.
Overview: Sorting data alphabetically can help organize information in a more accessible way. This Snipp demonstrates how to sort an array of objects alphabetically based on a specific field, such as name.
Implementation:
// Sort the names alphabetically
const sortedNames = namesWithAttributes.slice().sort((a, b) => a.name.localeCompare(b.name));
console.log(sortedNames);
// Output: [{ name: "Claus", gender: "male", language: "Danish" }, { name: "Henrik", gender: "male", language: "Swedish" }, { name: "Manuela", gender: "female", language: "Spanish" }, { name: "Norbert", gender: "male", language: "German" }, { name: "Saskia", gender: "female", language: "Dutch" }]
In this example, the slice() method is used to create a copy of the array, and sort() is used to sort the name field alphabetically.
Overview: After filtering data, you may only need specific fields, such as the name attribute. This Snipp explains how to use the map() method to extract specific fields from filtered data.
Implementation:
// Filter and extract only the names
const germanNames = namesWithAttributes
.filter(person => person.language === "German")
.map(person => person.name);
console.log(germanNames);
// Output: ["Norbert"]
Here, after filtering by language, we use map() to return just the name values from the filtered array. This results in an array of names that meet the filtering criteria.
Overview: Sometimes, filtering based on multiple attributes is necessary. This Snipp demonstrates how to combine different conditions in the filter() method to retrieve data that satisfies more than one criterion.
Implementation:
// Filter by gender and language
const femaleSpanishNames = namesWithAttributes.filter(person => person.gender === "female" && person.language === "Spanish");
console.log(femaleSpanishNames);
// Output: [{ name: "Manuela", gender: "female", language: "Spanish" }]
In this example, the array is filtered to include only objects where the gender is female and the language is Spanish. Using multiple conditions ensures that only the most relevant data is retrieved.
Overview: Filtering an array based on specific attributes (e.g., gender or language) allows you to retrieve only the relevant entries. This Snipp demonstrates how to use the filter() method in JavaScript to extract items that meet a single criterion.
Implementation:
// Filter by gender
const maleNames = namesWithAttributes.filter(person => person.gender === "male");
console.log(maleNames);
// Output: [{ name: "Norbert", gender: "male", language: "German" }, { name: "Henrik", gender: "male", language: "Swedish" }, { name: "Claus", gender: "male", language: "Danish" }]
Here, we filter the array to return only the objects where the gender is male. The filter() method is powerful for searching through arrays based on any condition.
Introduction: This Set provides a comprehensive guide on filtering and organizing data within JavaScript, specifically focusing on arrays of objects. The concepts covered include extending arrays with additional attributes, filtering based on specific criteria, and extracting particular fields (such as names). The solutions presented here will help you efficiently manage and manipulate data, making it easier to search, filter, and retrieve information clean and organized.
Overview: The final structure clearly separates the input handling from the list rendering, optimizing React performance by ensuring that components only re-render when necessary. The SearchPage acts as the parent that coordinates state changes, while the SearchInput and SearchList components are responsible for their respective tasks.
Overview of the Code:
// SearchPage.js
function SearchPage() {
const [debouncedQuery, setDebouncedQuery] = useState("");
const handleDebouncedQueryChange = (newQuery) => {
setDebouncedQuery(newQuery);
};
return (
<div>
<SearchInput onDebouncedQueryChange={handleDebouncedQueryChange} />
<SearchList q={debouncedQuery} />
</div>
);
}
// SearchInput.js
function SearchInput({ onDebouncedQueryChange }) {
const [searchQuery, setSearchQuery] = useState("");
const debouncedQuery = useDebouncedValue(searchQuery, 800);
useEffect(() => {
onDebouncedQueryChange(debouncedQuery);
}, [debouncedQuery, onDebouncedQueryChange]);
return (
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Search..."
/>
);
}
// SearchList.js
function SearchList({ q }) {
const { data, isFetching } = useSearchSnipps(q);
return (
<div>
{isFetching ? <Spinner /> : data.map((item) => <FeedItem key={item.id} item={item} />)}
</div>
);
}
This structure ensures efficient rendering, clear separation of concerns, and improved user experience in a React-based search interface.
This set demonstrates an effective approach to handling search functionality in a React application, focusing on optimizing performance by separating input handling and result rendering. By applying debouncing in the input field and managing state in a parent component, we ensure that only the necessary components re-render, providing a smoother experience for the user.
Overview: A critical aspect of optimizing React applications is separating concerns between components. By isolating the input field and the search results, we can ensure that only the necessary component re-renders. The SearchInput component handles the user input, while the SearchList component is responsible for displaying the search results. This separation allows for more efficient rendering and easier maintenance.
Implementation: In this approach, the SearchInput component is responsible for capturing the user’s search query and applying the debouncing logic. The debounced query is passed up to the SearchPage component, which then passes it down to the SearchList for displaying the results. This ensures that each component has a clear, focused responsibility.
function SearchInput({ onDebouncedQueryChange }) {
const [searchQuery, setSearchQuery] = useState("");
const handleInputChange = (e) => {
setSearchQuery(e.target.value);
};
useEffect(() => {
onDebouncedQueryChange(searchQuery);
}, [searchQuery, onDebouncedQueryChange]);
return (
<input
type="text"
value={searchQuery}
onChange={handleInputChange}
placeholder="Search..."
/>
);
}
function SearchList({ q }) {
const { data, isFetching } = useSearchSnipps(q);
return (
<div>
{isFetching ? <Spinner /> : data.map((item) => <FeedItem key={item.id} item={item} />)}
</div>
);
}
This structure ensures that the logic for capturing input and displaying results is handled separately, making the code easier to understand and maintain.
Overview: Managing state efficiently is key to ensuring React applications are performant and responsive. In this implementation, we separate the concerns of managing user input and fetching/displaying search results. The state for the search query is managed in the SearchPage component, while the search input is handled by the SearchInput component. This separation ensures that only the necessary components re-render when the state changes.
Implementation: The SearchPage component manages the query state and passes it down to both the SearchInput and SearchList components. When the SearchInput component detects a change in the input field, it propagates the debounced query to the SearchPage using a callback function. This avoids unnecessary re-renders of components that don't need to be updated.
import React, { useState, useEffect } from "react";
import SearchInput from "./SearchInput";
import SearchList from "./SearchList";
function SearchPage() {
const [debouncedQuery, setDebouncedQuery] = useState("");
const handleDebouncedQueryChange = (newQuery) => {
setDebouncedQuery(newQuery);
};
return (
<div>
<SearchInput onDebouncedQueryChange={handleDebouncedQueryChange} />
<SearchList q={debouncedQuery} />
</div>
);
}
This structure ensures that the SearchList component only re-renders when the debounced query changes, preventing unnecessary re-renders during the user’s typing.
Overview: Debouncing is a technique that limits the rate at which a function is invoked, especially in cases like search input, where every keystroke could trigger an expensive operation such as an API call or a state update. In this solution, debouncing is applied to the search input field, ensuring that the search query is only processed after the user has stopped typing for a specified period, thus reducing unnecessary re-renders.
Implementation: The SearchInput component is responsible for capturing user input. However, instead of immediately sending the input to the parent component or making API calls, we use a debouncing hook (useDebouncedValue) to delay updates until the user stops typing for a set period (e.g., 800ms).
import React, { useState, useEffect, useCallback } from "react";
import { useDebouncedValue } from "../../services/hooks/useDebouncedValue";
function SearchInput({ initialQuery, onDebouncedQueryChange }) {
const [searchQuery, setSearchQuery] = useState(initialQuery || "");
const debouncedQuery = useDebouncedValue(searchQuery, 800);
useEffect(() => {
onDebouncedQueryChange(debouncedQuery);
}, [debouncedQuery, onDebouncedQueryChange]);
const handleInputChange = useCallback((e) => {
setSearchQuery(e.target.value);
}, []);
return (
<input
type="text"
value={searchQuery}
onChange={handleInputChange}
placeholder="Search..."
/>
);
}
This implementation ensures that the parent component (SearchPage) receives the debounced query and only passes it to the child SearchList when the user has stopped typing for a period, optimizing performance.
Introduction
This set explores an efficient way to handle search functionality in a React application, focusing on the optimization of rendering performance during user input. It illustrates how separating concerns between the input field and the displayed search results helps reduce unnecessary re-renders, providing a smoother and more responsive user experience. The techniques discussed here include debouncing input, state management, and ensuring that only relevant components re-render.
Overview of the Optimization Approach
To optimize the rendering behavior in a React search feature, we separate concerns into two components: SearchInput and SearchList. By doing so, we achieve the following:
Benefits of the Approach
This approach provides several key benefits:
The useNavigate hook from React Router returns a function that lets you navigate programmatically, for example in an effect:
import { useNavigate } from "react-router-dom";
function useLogoutTimer() {
const userIsInactive = useFakeInactiveUser();
const navigate = useNavigate();
useEffect(() => {
if (userIsInactive) {
fake.logout();
navigate("/session-timed-out");
}
}, [userIsInactive]);
}
Button click
import { useNavigate } from 'react-router-dom';
...
const navigate = useNavigate();
...
<Button onClick={() => navigate('../user', { replace: true })}>Register</Button>
Reference
useContext is a React Hook that lets you read and subscribe to context from your component. React Context is a way to manage state globally.
useContext allows you to consume the context values within a functional component, making it more convenient and concise compared to using the Consumer component.
Here's an example of using React Context and the useContext hook:
import React, { createContext, useContext } from 'react';
// Create a context
const MyContext = createContext();
function ParentComponent() {
const contextValue = "Hello from Context!";
return (
<MyContext.Provider value={contextValue}>
<ChildComponent />
</MyContext.Provider>
);
}
function ChildComponent() {
// Consume the context using the useContext hook
const contextData = useContext(MyContext);
return <div>{contextData}</div>;
}
function App() {
return <ParentComponent />;
}
In this example, useContext is a hook that allows ChildComponent to access the context value provided by the ParentComponent without needing the Consumer component. So, while React Context itself is not a hook, it can be used in combination with hooks for more concise and modern React code.
Sometimes is helpful to know the scroll height of the window. Let's look at an example.
Suppose we have a component with two elements: a navigator and a main component.
import React from 'react';
import Nav from './Nav';
import Main from './Main';
export default const Page = () => {
return (
<div className = 'Page'>
<Nav/>
<Main/>
</div>
);
}
Let's suppose that Page.js is a flex-box, Nav.js is a sticky element, and Main.js has a position: absolute element inside of it.
If the element with absolute position is larger than the size of main, the sticky navigator will not work as expected (it won't stick).
We'll need to resize the Main.js component and make it as big as the scroll height of the window. To do so, we need to read scrollHeight property.
import React, { useEffect, useState } from 'react';
export default const Main = () => {
const [height, setHeight] = useState(0);
useEffect( () => { setHeight(document.documentElement.scrollHeight) });
return (
<div className = 'Main' style = {{height: `${height}px`}}>
<div className = 'Absolute'>This is an absolute positioned element.</div>
</div>
);
}
Now the main component will expand and the sticky element will work as expected.
In this Snipp we show how to create a loading spinner component in React JS using pure CSS.
1. Create the React component to display the spinner
// Spinner.jsx
import React from "react";
import "./spinner.css";
export default function Spinner() {
return (
<div className='container'>
<div className='loader'></div>
</div>
);
}
2. Add CSS styles for loading spinner animation
/* spinner.css */
.container {
display: grid;
justify-content: center;
align-items: center;
}
.loader {
border: 3px solid #f3f3f3;
border-top: 3px solid #3498db;
border-radius: 50%;
width: 25px;
height: 25px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
Additional Resources:
You can assign a new value to clear or reset a useRef in your React app. For example, if you have a useRef called myRef, you can reset it by setting it to null or any other value you want. Here's an example:
import React, { useRef } from 'react';
function MyComponent() {
const myRef = useRef(null);
function handleClick() {
myRef.current = null; // reset the ref
}
return (
<div>
<button onClick={handleClick}>Reset Ref</button>
</div>
);
}
In this example, we create a useRef called myRef and initialize it to null. Then, we define a handleClick function that sets myRef.current to null when the button is clicked. This effectively resets the ref.
Note: Resetting a ref may not always be necessary or desirable, and you should only do it if it makes sense for your specific use case.