How to modify this to not be two components in React - reactjs

NOTE: I HAVE REPLACED THIS QUESTION WITH ONE WITH MORE CLARITY AT THE LOCATION: Context not returned when referencing React component as function instead of JSX
I WOULD LIKE TO DELETE THIS BUT SO WILL NOT LET ME.
I have the following JavaScript file that is one React component calling another one nested inside it. I want to change this to not use the name of the nested component but instead create the internal component as an anonymous one.
I want to usr the JavaScript name and not return JSX.
Here is my original working component
const InsideComponent = () => {
return (
<div>
Inside Component
</div>
);
};
export default function Speakers() {
return (
<div>
<InsideComponent />
</div>
);
}
I've tried a few combinations including this below that do not work
export default function Speakers() {
return (
<div>
{
return (
{ InsideComponent()}
)
}
</div>
);
}

Using { inside the context of JSX stops the JSX syntax and begins a plain JavaScript expression. (Not a function - no return.) So from here
<div>
{
for the syntax to be valid, you'd need to have an expression that evaluates to a JSX element:
export default function Speakers() {
return (
<div>
{
(
<div>
Inside Component
</div>
)
}
</div>
);
}
But the nesting of a JavaScript expression isn't useful at all there - better to just insert the plain JSX instead.
export default function Speakers() {
return (
<div>
<div>
Inside Component
</div>
</div>
);
}

When you want to merge components, you just need to merge the JSX portion of it.
In your example, you can just do
export default function Speakers() {
return (
<div>
<div>
Inside Component
</div>
</div>
);
}

Why not this?
export default function Speakers() {
return (
<div>
<div>
Inside Component
</div>
</div>
);
}
Unless you're using the InsideComponent as part of other components, there is no need to separate the two. But if you want to, just use it like you would any other component.
export default function Speakers() {
return (
<div>
<div>
<InsideComponent />
</div>
</div>
);
}

export default function Speakers() {
return (
<div>
<div>
Inside Component
</div>
</div>
);
}
Is this is what you are looking for?

Related

Change the state of another component using functionnal components in React

I have a button in my header that has to switch the state of the lateral menu of the page (to know if it has to be shown or not). I found out on Internet how to do so using Class Components, but not with Functional Components, do you have any idea on how to achieve that ?
Here's a simplification of my actual code in order to reproduce my issue (I removed all useless code).
App.js :
function App() {
return (
<div className="App">
<Header />
<div>
<LateralMenu />
</div>
</div>
);
}
The Header component :
function Header() {
const [lateralIsOpen, setLateralIsOpen] = useState(true);
function changeLateralMenu() {
setLateralIsOpen(!lateralIsOpen);
}
return (
<header>
<div onClick={ changeLateralMenu }>
</header>
);
}
And the LateralMenu component :
function Header() {
const [lateralIsOpen, setLateralIsOpen] = useState(true);
return (
<section>
{ lateralIsOpen ? "open" : "closed" }
</section>
);
}
I tried (but maybe not correctly) to declare the lateralIsOpen State in the App component and sending it through props to my children componenents (Header & LateralMenu).
I also tried looking at this question (and a few others) which is pretty similar, but don't see how I can apply it in my case because (as I understand) he uses a button in the parent component, that changes a state in the parent component, and then send it to the children through props... Where in my case, the button to switch it is already in a child.
I'd suggest you to move the state out of the LateralMenu to the parent (App) and then just pass the toggle function to the Header to toggle it.
export default function App() {
const [lateralIsOpen, setLateralIsOpen] = useState(true);
return (
<div className="App">
<Header toggleLateral={() => setLateralIsOpen((prev) => !prev)} />
<div>
<LateralMenu isOpen={lateralIsOpen} />
</div>
</div>
);
}
function Header({ toggleLateral }) {
function changeLateralMenu() {
toggleLateral();
}
return (
<header>
<div onClick={changeLateralMenu}>click</div>
</header>
);
}
function LateralMenu({ isOpen }) {
return <section>lateral is {isOpen ? 'open' : 'closed'}</section>;
}
Codesandbox: https://codesandbox.io/s/eager-heyrovsky-z75njd

React children functional props not working

I am new to ReactJS, the following error reported in console:
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
What is wrong?
function Test({children}) {
return (
<div>
{children}
</div>
);
}
export default function App() {
return (
<div className="App">
<Test> {() => (<h1>Title</h1>)}</Test>
</div>
);
}
Part of the render props pattern is that the child component calls the children as a function in order to render it.
If you expect to have either normal ReactNodes or a function, you'll need to check to see if the children is a function to determine how to use it.
If you expect children will always be a function you can just call it without the type check first, though there will be an error if you pass in something that isn't callable.
function Test({children}) {
return (
<div>
{typeof children==='function'? children() : children}
</div>
);
}
function App() {
return (
<div className="App">
<Test>{() => (<h1>Title</h1>)}</Test>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root" />
In addition, you need to make sure there's no extra whitespace before the curly braces to set up the render props function, otherwise it is interpreted as ['', function(){}] which won't work:
<Test> {() => (<h1>Title</h1>)}</Test>
export default function App() {
return (
<div className="App">
<Test><h1>Title</h1></Test> // Change hehre
</div>
);
}

How to display the html of the children slot?

I've got this react component where I'm passing in a title and the children is a simple div with the word test.
export default function Home() {
return (
<div>
<main>
<SourceCode title="Header">
<div>test</div>
</SourceCode>
</main>
</div>
);
}
I want to display the HTML of whatever is in the children slot so in this example I want to to show <div>test</div>, I've tried using pre but I get the error TypeError: Converting circular structure to JSON
export default function SourceCode({ children, title }) {
return (
<div>
<div>{title}</div>
<div>{children}</div> // <== Here I want to render the markup, this works
<div>
<pre>{JSON.stringify(children)}</pre> // <== Here I want to show the markup
</div>
</div>
);
}
I have also tried
<pre>
<code>{children}</code>
</pre>
but this just shows test and I want it to show <div>test</div>
You could try with ReactDOMServer.renderToStaticMarkup
import ReactDOMServer from 'react-dom/server';
export default function SourceCode({ children, title }) {
const markup = ReactDOMServer.renderToStaticMarkup(children);
return (
<div>
<div>{title}</div>
<div>{children}</div> // <== Here I want to render the markup, this works
<div>
<pre>{markup}</pre> // <== Here I want to show the markup
</div>
</div>
);
}

Issue in react with an if / else

What am I missing to make it work?
I suppose the answer is very easy, but really, I'm starting in
React and still do not know why it does not work. If anyone knows, I am very grateful.
Thanks.
import React from 'react';
var a=30;
var b=20;
function App() {
return (
<div>
<h1>if or else</h1>
<c/>
</div>
);
}
export default App;
function c(a,b) {
if (a >= b){
return (
<div>
<h2> A is greater than B</h2>
</div>
);
}
else {
return (
<div>
<h2>B is greater than A</h2>
</div>
);
}
}
Hey you need to do it like this
import React from 'react';
function App() {
return (
<div>
<h1>if or else</h1>
<C a={20} b={30}/>
</div>
);
}
export default App;
function C({a, b}) {
if (a >= b){
return (
<div>
<h2> A is greater than B</h2>
</div>
);
}
else {
return (
<div>
<h2>B is greater than A</h2>
</div>
);
}
}
First, react components need to start with a capital letter, otherwise the React renderer will treat it as plain HTML.
Change your function declaration to:
function C(a,b) {}
And change your JSX where you call that component to:
<C/>
Second, a component must take a single argument (the props), but your component takes two arguments. And then where you call the component, you don't currently pass in any props.
So make your component take props as a single object:
function C(props) {
if (props.a >= props.b) {
//...
And now pass the props in where you invoke the component:
<C a={a} b={b} />

Custom namespaced attribute in JSX/React

As I already figured out, React's JSX doesn't support namespace tags by default. But lets say I have the following component:
render() {
return (
<div><!-- This should contain th:text -->
...
</div>
);
}
and I want this component to be rendered to:
<div th:text="value">
...
</div>
How can I achieve, that th:text="value" will be added to the rendered output?
Found the solution a few minutes later:
const i18n = {
"th:text": "${#foo.bar}"
};
render() {
return (
<div {...i18n}>
...
</div>
);
}

Resources