If we want to write multiple JSX elements we must wrap it with parent element or React Fragment element to be rendered successfully , Is there any way to write multipe jsx elements without need to wrap it with any parent or fragment element (like maybe make the fragment by default behind the scene without need to write it ) ,
function CustomBtn() {
return (
<h1>CustomBtn</h1>
<h1>CustomBtn</h1>
)
}
i know this will give Parsing error: Adjacent JSX elements must be wrapped in an enclosing tag
i know that it's useless , because we can just use react fragment , but it's like a training task to dig deeper into react configuration
i think in babel , webpack or react dom packages but i can't solve it , any ideas ?
Thanks
This is a good idea. But this is not customizable for the following reason.
React team made the interface of a component to be a single ReactNode. But for some functions, they also allow for an array of nodes, ReactNode[]. To be honest, internally they do support array, otherwise you won't be able to do {arr.map(v => <div />).
Therefore this is not something that you like or not, it's the interface definition of a React component. Imagine you design the component, you can choose to accept an array or a single. If you were the author, you could make that happen ;)
NOTE:
deep down there's another reason, each component accepts a ref. The ref is the DOM element reference, so a single mapping from one ref to a single React node is a more straightforward implementation.
You can return array:
function CustomBtn() {
return [
<h1>CustomBtn</h1>,
<h1>CustomBtn</h1>
]
}
Related
I simulated my Context + DND problem in https://codesandbox.io/s/adoring-booth-33vqo . I have other components which will be added to this example and I will use a Context hook to share values across the page.
After the initial render, everything looks fine. The idea of the list is to change the order within itself and when ones changes the order with drag-drop, it throws an "Invalid Hook" error.
So the (first) real question is, what is triggering this error which is linked to the line
const { lang1Library, updateLang1Library } = useContext(LangContext)
;
Thanks in advance for your help.
Geo
It's not a good approach to provide a link for the whole project even if it is small. But I had a quick look and there's at least one thing you're doing wrong:
// DragEndFct.js
export default function DragEndFct(result, libName) {
const { lang1Library, updateLang1Library } = useContext(LangContext);
This is not React component, but it uses a hook - and it is wrong. Hooks have a special meaning in React and should be used properly (Rules of Hooks).
You can't use hooks inside regular functions and expect them to work. That is why you are getting that error.
So, there are many ways you can try to fix this. For instance, DragEndFct is a regular function, you can declare more arguments and pass stuff you get from context:
// you are using it in components right ?
function DragEndFct(result, libName, param3, param4) {}
// so you probably have access to the context there
// and can pass data from the context when you call it.
// something like this
onDragEnd={function (result) {
console.log();
DragEndFct(result, StaticVars.LANG1_LIBRARY_NAME, lang1Library, updateLang1Library);
}}
You could even make DragEndFct to be a React component - it can just return null (which means no UI will be rendered) but in that case you will have hooks and all other stuff there. It really depends on what you need and how you will use it.
I'm going through a book to better learn React and came across a surprising example. I previously thought that in order to render an array of anything in React, we need to map each element of the array, and pass them keys (I know keys aren't absolutely mandatory but a best practice so React knows which element to re-render upon change.)
But here is a working example of an array being rendered without needing to do anything special to it:
const Tail = ({number, children}) => (
<div>
Last {number} children:
{React.Children.toArray(children).slice(-number)}
</div>
)
Is this something special about children? Why is React able to render an array like this? There aren't even keys specified!
So React.Children provides utilities like toArray, map, forEach etc for dealing with the children props data structure.
In this case the toArray:
Returns the children opaque data structure as a flat array with keys assigned to each child. Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice this.props.children before passing it down.
Here are the docs if you want to read more: https://reactjs.org/docs/react-api.html
I'm trying to make a scene graph in React that supports nesting components. Something along the lines of:
<SceneNode>
<SceneNode>
<Thing/>
</SceneNode>
<SceneNode>
<Thing/>
</SceneNode>
</SceneNode>
When a SceneNode is mounted I need a way for it to know at what "depth" it is. Is there a way within a component to access that information? e.g.:
function SceneNode({children}:{children:ReactNode}) {
const depth = useCallDepth(); // <- some magic function that lets me know the level of nesting for this node
return <div>{children}</div>
}
NOTE: I've tried the following:
Context: Can't get it to work without having each node create its own context but since context is referenced statically in React I can't access the dynamically created parent contexts from children.
Refs: The nesting of components should be reflected in the DOM elements they produce, but I can't figure out how to determine what the associated component is for a given DOM element - i.e. is this div a SceneNode or just a random div? (I suppose I could encode it in an attribute or id, but I was hoping for something a little cleaner and less invasive)
Manual: I can manually specify which nodes are parents (e.g. <SceneNode parent={true}/> but that's pretty error prone.
It is possible to use context for this: Demo
If, as a thought experiment, I were to write my own createElement implementation for JSX, what might support for implicit context look like?
In particular, I can't figure out how with the limited means of JSX's createElement signature, contexts can be independent for different subtrees. (It appears React's Context handling has become more elaborate in recent versions; I'm mostly interested in the seemingly more straightforward mechanisms of earlier versions.)
This might be used to automatically determine heading levels, for example:
<Section title="Hello World">
<Card title="Details" />
</Section>
<Card title="Example" />
Here Card would automatically generate <h3> and <h2>, respectively, by relying on something like context.headingLevel.
A very nice question, that shows how different is the concept of creating React Elements to actually executing the render functions (either the .render method of class components or simply the main body of a functional component).
In JSX itself (which is just React.createElement(…)) there‘s no concept of “context” at all. It comes into existance only when the components are rendered. It is indeed a duty of the React Renderer (such as React DOM or React Native) to actually implement Context APIs.
If you remove the ability to store states and to update the UI you are left with a minimal React implementation that only “renders once”, but perfectly fine to understand the problem at hand.
Everytime the React Renderer needs to render a React Elements tree (such as one built with JSX) it passes every single element and transforms it into a DOM structure, but when it encounters a component node (not a “native” element) it needs to render it to obtain its React Element sub tree, and swap the original node with it.
It’s in this specific moment that React can keep track of which Context values to pass to which components, since it is traversing the tree.
So, to answer directly your question, you can’t implement context in the “element creation phase”, inside your JSX implementation, you need to do it in a subsequent phase when you can traverse the tree.
If you were trying to build an “immediate JSX” you probably have something like this:
function createElement(type, props, ...children) {
props = { children, ...props };
if (typeof type === 'function') {
return type(props);
} else {
return { type, props };
}
}
In thise case you will not be able to implement an API similar to context, because the execution order is inner-then-outer:
const div = createElement('div', {}, createElement(Card, {}));
// identical to
const card = createElement(Card, {}); // inner, and then…
const div = createElement('div', {}, card); // outer
I encountered this problem when writing a .jsx file using devextreme-react.
I am using React to develop web, and I have an Array called "ServerStatusList" containing "server-status" objects in the following form:
{
server: String,
online: Number,
offline: Number,
vendor: String
}.
Now, I want to use each "server-status" object to generate a "Circular Gauge" chart, using the Devextreme-react library. So what I did was first creating an array react element using the "map" function, mapping each 'server-status' in the 'serverStatusList' to a CircularGauge element.
My intended effect is that a list of gauges appear on my web page.
const gaugeItems = vendorStatusList.map((i, index) => (
<CircularGauge
value={i.online}
subvalues={[i.online]}
>
</CircularGauge>
));
Then in my JSX file, in the render9() {} function, I wrote this:
return(
<Paper>
{gaugeItems}
</Paper>
);
However, I got the error message:
Objects are not valid as a React child (found: object with keys {server, online, offline, vendor}). If you meant to render a collection of children, use an array instead.
Does anyone know what the error means? I think my "gaugeItems" in between the tag is an array, as I checked it with "typeof". I am guessing that this method does not work in cases when the things in the list are objects, but only in the cases when the things in the list are primitive-typed items. Does anyone know what happens?