React children functional props not working - reactjs

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>
);
}

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

How to modify this to not be two components in React

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?

Why Won't This Render as JSX?

I have a string variable, with this HTML code like so:
this.state.contents:
<p>This Handbook is designed to provide you with information about your employment at {this.props.clientName} and its affiliates and subsidiaries (referred to throughout this Handbook as “{this.props.clientName}” or the “Company”).</p>
I pass it to a child component like this:
<Policy key={filteredPolicy.id} id={filteredPolicy.id} contents={filteredPolicy.contents} clientName={this.state.client}/>
The child component is this:
<Card.Body className="content" >{this.props.contents}</Card.Body>
But in the component, it renders as the string and just shows all the HTML tags. How do I get it to actually render correctly as HTML code? A second issue is the variables of {this.props.clientName} also do not show up... it just literally renders {this.props.clientName} as a string. It all works correctly if I just do it as HTML. But when I try to do it this way, no dice.
While you can still use dangerouslySetInnerHTML to achieve it like this, it's not recommended
function Child({ data }) {
return <div dangerouslySetInnerHTML={{__html: data}}></div>;
}
const test = "test-data";
export default function App() {
const [data] = useState(`<div>${test}</div>`); // note the ${} (template literal) here instead of {}, because this is a string, not React component
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Child data={data} />
</div>
);
}
Live example
Define a renderData function inside Parent component to render your html, pass it to Child as a prop, and call that renderData function here. You can use your state, props inside that renderData function as you want.
So the above example can be rewrite like this
function Child({ renderData }) {
return <div>{renderData()}</div>;
}
const test = "test-data";
export default function App() {
const renderData = () => {
return (
<div>{test}</div>
)
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Child renderData={renderData} />
</div>
);
}
Live example

How to identify React component tags after build in a CRA app?

I would like to create and use this component in React with ES6:
<Menu>
<MenuHeader>Hi</MenuHeader>
<MenuItem>Hello</MenuItem>
<MenuFooter>End</MenuFooter>
</Menu>
I've defined a component to handle this structure:
export class Menu extends React.Component {
render() {
return (
<div ...>
<div ...>
{HOW TO SELECT HEADER?}
</div>
<div ...>
{HOW TO SELECT ITEM?}
</div>
<div ...>
{HOW TO SELECT FOOTER?}
</div>
</div>
)}
}
It's okay to iterate over children and select by type.name while running on the dev server without transpilation:
{ React.Children.map(this.props.children, child => { return child.props.type === 'MenuItem' ? <>{ child }</> : '' } ) }
But it does not work after building it (cause of uglify/minify process).
For example, Semantic UI React handles it well - but it uses interfaces and written in TypeScript so I cannot use it as reference.
And one more thing (ah Steve:): I do not want to use npm eject.
This is normally done by allowing the compound components inside them to render their own children and Menu would just render the children it gets, hence maintaining the order.
You might want to share the state of things happening between the Header, Body and Footer, so we add a ContextProvider to the Menu component, so they can all share common state.
const rootEl = document.getElementById('root');
const { render } = ReactDOM;
const { createContext } = React;
function MenuHeader({ children }) {
return (
<header className="menu-header">
{children}
</header>
)
}
function MenuBody({ children }) {
return (
<div className="menu-body">
{children}
</div>
)
}
const MenuContext = createContext();
Menu.Header = MenuHeader;
Menu.Body = MenuBody;
function Menu({ children }) {
return (
<MenuContext.Provider value={null}>
<div className="menu-wrapper">
{children}
</div>
</MenuContext.Provider>
);
}
function App() {
return (
<Menu>
<Menu.Header>Menu Header</Menu.Header>
<Menu.Body>Menu Body</Menu.Body>
</Menu>
);
}
render(<App />, rootEl);
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root" />
Another common technique used by Frameworks like Ant.Design is to map over the children and add common props to them (although context would be the better solution in my opinion)

Can I call react component in a react component

I'm just start learning react js. Just wondering is it a good way to invoke a component inside another component?
Most React projects will start out by giving you an App.js component where you can start writing code. There, you can invoke other components using JSX syntax. Like this:
function App() {
return (
<div>
<Header />
<Main />
<Footer />
</div>
)
}
Working example below:
// Main application component
function App() {
return (
<div>
<Header />
<Main />
<Footer />
</div>
)
}
// Header component
function Header() {
return (
<header>
<h1>My first React App</h1>
</header>
)
}
// Main component
function Main() {
return (
<main>
<p>Stuff and stuff go here..</p>
</main>
)
}
// Footer component
function Footer() {
return (
<footer>
<p>Copyright 2020</p>
</footer>
)
}
ReactDOM.render(
<App />,
document.getElementById('app')
)
<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="app"></div>
Note: You may also see class components instead of functional ones. They look something like this:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
// some state goes here..
}
}
render() {
return (
<div>
<Header />
<Main />
<Footer />
</div>
)
}
}
You generally want to compose components using JSX. There is a good write up on the react docs. https://reactjs.org/docs/composition-vs-inheritance.html
const ComponentOne = () => <div>hi</div>
const ComponentTwo = () => <div>two</div>
const ComponentThree = () => (
<>
<ComponentOne />
<ComponentTwo />
</>
)
In the case that you want to learn, or start to le I recommend this https://reactjs.org/docs/getting-started.html. If you have another question please let me know.
React has two type of components: Function based and Class based. I will explain Function based components.
Example:
import React, {Fragment} from 'react';
function ComponentB(){
return (
<p>Hello i'm component B</p>
)
};//end;
function ComponentA(){
return (
<Fragment>
<h1>hello i'm component A</h1>
<ComponentB />
</Fragment>
)
};//end;
export default ComponentA;

Resources