I am using microfrontend, In that I have a main container which uses these two Microfrontend component, and these three component are in different repo.
I have one React component in one repo:
class CustomForm extends React.Component {
...
render() {
return (
<div>
{this.props.component}
</div>
);
}
}
And I have a different component In another repo(other Microfrontend component) that use it:
class SomeContainer extends React.Component {
render() {
let someObjectVariable = {someProperty: 'someValue'};
return (
<CustomForm
component={<SomeInnerComponent someProp={'someInnerComponentOwnProp'}/>}
object={someObjectVariable}
/>
);
}
}
Is there a way to pass props between two different Microfrontend component?
Your proptype for component in CustomForm will need to accept ReactNodes.
But you should be able to pass it through as a function (Meaning without the < and />:
if you do not need to pass any custom props, you can just call
<CustomForm component={SomeInnerComponent} .... />
If you need the custom props, you can wrap it in another function and just pass that through:
<CustomForm component={ () => {
return <SomeInnerComponent someProp={'someInnerComponentOwnProp'}/>;
}} ...... />
The reasoning behind this is that because Functional components in React are actually just Functions, you can pass through a component as a prop without the < or /> and then it will just execute that as a function.
Related
I'm using ReactJS since just a week or two and I'm now trying to build an App using it.
I think I understood how I should make a Child Component communicates with its Parent Component passing a function as a prop.
But now I'd like to do something different and make 2 sibling Components communicate with each other.
I know I could achieve this using their common Parent Component, but I'd really love to declare some methods on one of those sibling Components and reuse them all over the App.
So here is my idea and my question: can I safely set the state of a Parent Component putting there the "this" from Child Component and then use this variable on other Components?
I already wrote this code and it's working, but I don't understand if this is a good approach or a bad one.
Here some parts of my code to let you see what I'm doing.
Parent Component:
class App extends Component{
state = {}
render(){
return <Router>
<div id="page">
<Header app={this} />
<div id="main" class="row">
<Sidebar app={this} />
<Content app={this} />
</div>
<Footer app={this} />
</div>
</Router>
}
}
Sidebar:
class Sidebar extends Component{
state = {menu: []}
componentDidMount() {
this.props.app.setState({sidebar: this})
}
populateSidebar = (sidebar) => {
this.setState({menu: sidebar})
}
render(){
if (this.state.menu.length == 0){
return null;
}
return (
<sidebar class="col-3">
<ul>
{this.state.menu.map(item => <li><Link to={item.url}>{item.text}</Link></li>)}
</ul>
</sidebar>
)
}
}
User Component (it's a Child of the Content Component. The Content Component just does some routing based on the url):
class User extends React.Component {
async componentDidMount() {
await this.props.app.state.sidebar
this.props.app.state.sidebar.populateSidebar(
[
{
url: "/user/add",
text: "Add new user"
},
{
url: "/user/list",
text: "Users list"
}
]
)
}
async componentWillUnmount() {
await this.props.app.state.sidebar
this.props.app.state.sidebar.populateSidebar([])
}
render() {
return (
<div>
<UserAdd />
<UserList />
</div>
);
}
}
I know that what I'm accomplishing here is so basic that I could totally do it in a different way, for example putting the sidebar menu as an array on the Parent Component's state. But let's say that I want a bunch of methods on Sidebar and let all my other components using them without rewriting too much code. Is this a bad idea?
I'd really love to declare some methods on one of those sibling
Components and reuse them all over the App.
A better approach is to create a helper class with some static methods and use it everywhere across your components, this class even doesn't have to be a react component just a regular ES6 class, for example:
class MyHelper {
static doSummation(num1, num2) {
return num1 + num2;
}
static doMultiplication(num1, num2) {
return num1 * num2
}
// ... other helper methods as you want
}
export default MyHelper;
Then in your React components you can import it and use its helper methods:
import React, {Component} from 'react';
import MyHelper from './MyHelper';
class MyComponent extends Component {
render() {
return (
<div>
{MyHelper.doSummation(1, 2)};
</div>
);
}
}
You can even, for better organization, have as many helper classes as you want, for example MathHelper, StringFormattingHelper, etc...
(this question differs to 'is it possible to use a component inside another', this question is 'can I define a component inside the definition of another', it is not a duplicate of 'Can I write Component inside Component in React?')
Is it possible to define a component inside the definition of another component? This way I can use the props of the outside component in the inner component. It would keep the code more concise. Something like the following...
class AComponent extends Component {
CustomButton = (props) => {
let { disabled, ...otherProps } = props // <-- props of the inner component
const {isDisabled, currentClassName} = this.props // <-- props of the main component
return (
<button
className={className}
disabled={isDisabled}
{...otherProps}>
</button>
)
}
render() {
return (
<div>
<CustomButton>Add something</CustomButton>
<CustomButton>Delete something</CustomButton>
<CustomButton>Edit</CustomButton>
</div>
)
}
}
If the custom button was defined on its own (the usual way of defining components) I would have to do something like below which is ok but more verbose and less dry as I repeat the definition of {...buttonProps} for each component
let buttonProps = {
className: this.props.currentClassName,
disabled: this.props.disabled
}
return (
<div>
<button {...buttonProps}>Add something</button>
<button {...buttonProps}>Delete something</button>
<button {...buttonProps}>Edit</button>
</div>
)
While yes, it's possible to define one function component inside another function component, this is not recommended.
Referring to the ReactJs docs:
reactjs.org/docs/components-and-props
reactjs.org/docs/conditional-rendering
Most, if not all, examples show child components being defined outside of the parent component.
Defining a component inside another will cause the child component to be re-created on mount and unmount of the parent, which could cause unexpected behavior if the child is using props from the parent, and cannot handle if those props are suddenly undefined.
It's best to define components separately.
Yes! I needed to define the function component in the render method...which makes sense
class AComponent extends Component {
render() {
const ButtonLocal = (props) => {
const {isDisabled, currentClassName} = this.props
return (
<Button
disabled={isDisabled}
className={currentClassName}
{...buttonProps}>
</Button>
)
}
return (
<div>
<ButtonLocal>Add something</ButtonLocal>
<ButtonLocal>Delete something</ButtonLocal>
<ButtonLocal>Edit</ButtonLocal>
</div>
)
}
}
Very much possible to add components inside a parent component. Consider following example:
<ParentComponent style={styles}>
<ChildComponent style={styles} {...props} />
</ParentComponent>
I may be over thinking this, but I am curious if importing a child component directly is bad practice with regards to coupling and testing.
Below is a simple example:
import Header from './header.jsx';
class Widget extends React.Component {
render() {
return (
<div>
<Header></Header>
<div>{this.props.importantContent}</div>
</div>
)
}
}
To me it looks like there is now coupling between Widget and Header. With regards to testing, I don't see an easy way to mock the Header component when testing the Widget component.
How do other larger React apps handle cases like this? Should I pass Header in as a prop? If using react-redux, I can inject header with the Connect method like below to reduce boilerplate. Is that sound?
import { connect } from 'react-redux';
import Header from './header.jsx';
class Widget extends React.Component {
render() {
return (
<div>
{this.props.header}
<div>{this.props.importantContent}</div>
</div>
)
}
}
const mapStateToProps = state => {
return {
header: Header
}
}
export default connect(mapStateToProps)(Widget)
I am interested is simple doing what the community is generally doing. I see that one solution is doing shallow rendering to test on the main part of the component and not the child components using something like Enzyme.
Thoughts or other ideas?
Passing elements / components as props is a good idea. Having default props is a good idea too:
const Widget = ({
header = <div>Default Header.. </div>,
content = <div>Default Content.. </div>
}) =>
<div>
{header}
{content}
</div>
Then elsewhere in your app:
<Widget header={<Header title="Foo" />} content="content from props" />
No need to inject using connect
You can also pass a component, not just an element if you want to interact with props / send data back to parent:
const Widget = ({
Header = props => <div>Default Header.. </div>,
Content = props => <div>Default Content.. </div>
}) =>
<div>
<Header />
<Content />
</div>
Elsewhere:
<Widget Header={Header} Content={props => <Content />} />
As long as the component always renders the same thing it can be directly rendered as a child rather than the parent.
If all other portions of the Component remain constant and only the Header can be different across pages then you could actually implement it as an HOC instead of passing it as a props
const MyCompFactory = ({CustomHeader = DefaultHeader}) => {
return class Widget extends React.Component {
render() {
return (
<div>
<CustomHeader/>
<div>{this.props.importantContent}</div>
</div>
)
}
}
}
and use it like
const CustomComponent = MyCompFactory({CustomComponent: Header})
as long as testing is concerned in your case, you could just shallow render your component and then Search if the Header component is rendered something like
import Header from 'path/to/header'
const component = shallow(
<Widget {...customProps}/>
)
test('test' , () => {
expect(component.find(Header).exists()).toBe(true)
})
I am looking for a way to get all children out of a React Component.
Example:
class MyComponent extends React.Component {
render() {
<div>
<h1>Welcome!</h1>
<ChildComponent />
</div>
}
}
const renderedComponent = <MyComponent />
React.Children(renderedComponent.props.children).forEach(() => {
// Some logic
});
Problem: renderedComponent.props.children is empty. Is there any way to get the children in a way like this ?
My goal is to get all children recursively.
Take a look at ReatDOMServer It seems like you will want to render your component to a string via renderToString and then parse the results with something like jQuery.parseHTML
wonder if it is possible to pass a component a property as following
ReactDOM.render(
<ContainerBox anotherComponent={<AnotherComponent />} />, document.body);
And then insider the ContainerBox I want to pass AnotherComponent a property in following way.
class ContainerBox extends React.Component {
clickHandler() {
//does something fun
}
render () {
return (
this.props.anotherComponent(this.clickHandler) //<----- is it possible to pass properties from here?
);
}
}
Is it possible to pass things from ContainerBox to AnotherComponent from that position?
ContainerBox has a clickHandler function which I want to pass to AnotherComponent. It is possible to do so if I move <AnotherComponent /> to inside of render() instead. But then I cannot reuse ContainerBox for other components without first copying the whole ContainerBox.
Does it make sense? Hope you can understand.
UPDATED code example
Yes, that is possible. However, it's more common to do it like this
ReactDOM.render(
<ContainerBox><AnotherComponent /></ContainerBox>, document.body);
And in ContainerBox
class ContainerBox extends React.Component {
render () {
return (
this.props.children
);
}
}
Read more about reacts this.props.children here: https://facebook.github.io/react/docs/multiple-components.html#children
Edit:
I just want to point out that in this example, we are not passing a component, but an element (the result of rendering the component).
It's also possible to pass components, like this:
<Foo buttonComponent={FancyButtonComponent} />
and in Foo:
render() {
Button = this.props.buttonComponent;
return (
<div>
...
<Button />
</div>
);
}