I'm rendering several react "snippets" on one page
ReactDOM.render(<MainNavSearchApp />, document.getElementById('main-nav-search-app'));
ReactDOM.render(<NavSearchBrandsApp />, document.getElementById('main-nav-search-brands-app'));
and want to use one context for them
class MainNavSearchApp extends React.Component {
render() {
return (
<div>
<NavSearchContextProvider>
<MainNavSearch />
</NavSearchContextProvider>
</div>
);
}
}
export default MainNavSearchApp;
class NavSearchBrandsApp extends React.Component {
render() {
return (
<div>
<NavSearchContextProvider>
<NavSearchBrands />
</NavSearchContextProvider>
</div>
);
}
}
export default NavSearchBrandsApp;
but if I update the context in on of the apps, it does not get updated in the other. As I understand, React creates two "clone" independent contexts. Can multiple instances use the same context?
Yes you can, as data in React flows down, they must have a common parent in order to share same context data.
This is commonly called a “top-down” or “unidirectional” data flow. Any state is always owned by some specific component, and any data or UI derived from that state can only affect components “below” them in the tree.
Therefore, the common parent should use ReactDOM.createPortal, and render the provider, while other components will be his children.
<body>
<div id="root"></div>
<div id="app1"></div>
<div id="app2"></div>
</body>
// Common parent - MUST
function Root() {
return (
<Context.Provider value={42}>
{ReactDOM.createPortal(<App1 />, document.getElementById("app1"))}
{ReactDOM.createPortal(<App2 />, document.getElementById("app2"))}
</Context.Provider>
);
}
// MainNavSearchApp
function App1() {
const val = React.useContext(Context);
return <>App1: {val}</>;
}
// NavSearchBrandsApp
function App2() {
const val = React.useContext(Context);
return <>App2: {val}</>;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Root />, rootElement);
Related
I have two stateful components:Grid and Item.Item is rendering by Grid and have props which reference to method (handler) defined in Grid <Item example={this.props.inGridHandler} />
Ok. But what if I have third stateful component let's name it Handy and I want that inGridHandler is defined not in Grid component as before but in Handy. How to achieve this with preserving all this structure ?
class Grid extends Component{
ingridHandler=()=>{
console.log('I want to be defined in Handy Component, not here');
}
Render(){
Return(
`<Item example={this.inGridHandler} />`
);
}
};
export default Grid;
class Handy extends Component{
inGridHandlerWantToBeDefinedHere=()=>{
console.log("I want to be defined here and pass to Grid component as props of Item component which is rendered there'
}
render(){
return(
)
}
}
Here is what you want if I understand you right. This is a very simple process. You are just passing the props all the way down. But, as I try to explain in my comments in the future you should think better approaches if you don't want to pass the props like this.
class Handy extends React.Component {
inGridHandler = () => {
console.log("ingridhandler");
};
render() {
return <Grid inGridHandler={this.inGridHandler} />;
}
}
class Grid extends React.Component {
render() {
return <Item inGridHandler={this.props.inGridHandler} />;
}
}
const Item = props => (
<button onClick={props.inGridHandler}>Click me and look the console.</button>
);
ReactDOM.render(
<Handy />,
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"></div>
I would like to pass state to a sibling or even a grandparent whatever.
I have 3 components. Inside Header, I have a button with an onClick function to toggle a Dropdown Menu inside Navigation. And by the way, I would like to pass the same state to AnotherComponent.
How to pass state (such as isDropdownOpened) from Header to Navigation and AnotherComponent?
<div>
<Header />
<Navigation />
<div>
<div>
<div>
<AnotherComponent />
</div>
</div>
</div>
</div>
You have different approaches to address this situation.
Keep the state in the top component and pass it to children through props
Use a state container to keep and share your application state among components (e.g. https://redux.js.org/)
Use the new React Context feature. Context provides a way to pass data through the component tree without having to pass props down manually at every level.
That's the exact reason why "React Hooks" have been developed (and hyped by the community 😉), but don't use them yet in production, they are still in early development (alpha) and their specification/implementation might be changed!
You problem can be solved using the awesome “React Context“ API which allows to pass data to components no matter how deep they are nested in the tree.
To get to know to context read the extensive documentation linked above. I'll only explain a small and quick example here:
Create a context component and export the consumer
App.jsx
import React from "react";
// The initial value can be anything, e.g. primitives, object, function,
// components, whatever...
// Note that this is not required, but prevebents errors and can be used as
// fallback value.
const MyContext = React.createContext("anything");
// This component is the so called "consumer" that'll provide the values passed
// to the context component. This is not necessary, but simplifies the usage and
// hides the underlying implementation.
const MyContextConsumer = MyContext.Consumer;
const someData = { title: "Hello World" };
const App = ({ children }) => (
<MyContext.Provider value={someData}>{children}</MyContext.Provider>
);
export { MyContextConsumer };
export default App;
Import the created consumer in any component and use the provided value
AnotherComponent.jsx
import React from "react";
import { MyContextConsumer } from "./App";
const AnotherComponent = () => (
<div>
<MyContextConsumer>{({ title }) => <h1>{title}</h1>}</MyContextConsumer>
</div>
);
export default AnotherComponent;
Render the app with both context components
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import AnotherComponent from "./AnotherComponent";
const Root = () => (
<App>
<AnotherComponent />
</App>
);
const rootElement = document.getElementById("root");
ReactDOM.render(<Root />, rootElement);
The component will render a level 1 heading with the "Hello World" text.
How to pass state (such as isDropdownOpened) from Header to Navigation and AnotherComponent, please ?
You hold the state in an ancestor of Header and pass that state to Haeader, Navigation, and AnotherComponent as props. See State and Lifecycle and Lifting State Up in the documentation.
Example:
const Header = props => (
<div>
<span>Header: </span>
{props.isDropdownOpened ? "Open" : "Closed"}
</div>
);
const Navigation = props => (
<div>
<span>Navigation: </span>
{props.isDropdownOpened ? "Open" : "Closed"}
</div>
);
const AnotherComponent = props => (
<div>
<span>AnotherComponent: </span>
{props.isDropdownOpened ? "Open" : "Closed"}
</div>
);
class Wrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
isDropdownOpened: false
};
}
componentDidMount() {
setInterval(() => {
this.setState(({isDropdownOpened}) => {
isDropdownOpened = !isDropdownOpened;
return {isDropdownOpened};
});
}, 1200);
}
render() {
const {isDropdownOpened} = this.state;
return (
<div>
<Header isDropdownOpened={isDropdownOpened} />
<Navigation isDropdownOpened={isDropdownOpened} />
<div>
<div>
<div>
<AnotherComponent isDropdownOpened={isDropdownOpened} />
</div>
</div>
</div>
</div>
);
}
}
ReactDOM.render(
<Wrapper />,
document.getElementById("root")
);
<div id="root"></div>
<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>
There are some other options, which Arnaud usefully provides in his answer.
Like how TJ Said, use the state of the parent component. That way one state is shared by all the sub components, which is what you wanted I presume.
class ExampleParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
isDropdownOpened: false
}
}
toggleDropdown() {
this.setState({
isDropdownOpened: !isDropdownOpened
});
}
render() {
return (
<div>
<Header open={isDropdownOpened} toggleDropdown={ this.toggleDropdown }/>
<Navigation open={ isDropdownOpened}/>
<div>
<div>
<div>
<AnotherComponent open={ isDropdownOpened} />
</div>
</div>
</div>
</div>
);
}
class Header extends React.Component {
render() {
return (
<div>
<button onClick={ this.props.toggleDropdown }>TOGGLE ME</button>
{ isDropdownOpened && (
<h1> DROPPED </h1>
}
</div>
);
}
}
You can only use this.state.variableName to access
<ChildComponent data={this.state.name} />
And to pass functions
<ChildComponent data={this.HandleChange} />
First Send the data from the first child to the common parent using callback
function and then send that received data (stored in state in parent component)
to the second child as props.
you can also read this article - https://www.pluralsight.com/guides/react-communicating-between-components
Is the following an anti pattern in React? I like the pattern because it gives me context in static functions when a component has been instantiated. Then later I can import the class and call a static method to modify state. Or can this be done in a better way?
// componentA.js
function bleedContext() {
ComponentA.staticMethod = ComponentA.staticMethod.bind(this)
}
export default class ComponentA {
static staticMethod() {
this.setState({foo: 'bar'})
}
constructor() {
this.state = {}
bleedContext.call(this)
}
render() {
return (
...
)
}
}
// componentB.js
import ComponentA from 'path/to/componentA'
export default class ComponentB {
handleClick() {
ComponentA.staticMethod()
}
render() {
return (
<button onClick={this.handleClick} />
)
}
}
This is clearly an antipattern and possibly a mistake, depending on conditions. Static class method shouldn't operate with class instance. staticMethod is bound to specific component instance and uses setState, this could be only justified a class is a singleton (though a singleton is often an antipattern, too). This will result in bugs and memory leaks if more than one class instance is expected, and every React component is expected to have more than one instance, at least for testing.
A proper way for two independent components to interact with each other in React is to have a common parent component that provides this interaction, e.g.:
class ModalContainer extends Component {
modalRef = React.createRef();
render() {
return <>
<Modal ref={this.modalRef} />
<SomeComponentThatUsesModal modalRef={this.modalRef} />
</>;
}
}
The problem with example above is that this will require to pass modalRef prop deeply if <SomeComponentThatUsesModal> is nested.
This problem is solved with React context or other third-party global state solutions like Redux.
This can be done with React 16.3 context API, considering that Modal class instance has open method:
const ModalContext = React.createContext();
function getModal(modalRef) {
return {
open: data => modalRef.current.open(data);
close: () => modalRef.current.close();
}
}
class ModalContainer extends Component {
modalRef = React.createRef();
render() {
return <>
<Modal ref={this.modalRef} />
<ModalContext.Provider value={getModal(this.modalRef)}>
{this.props.children}
</ModalContext.Provider>
</>;
}
}
Then for any deeply nested component modal object with open and close methods will be available via context:
const SomeComponentThatUsesModal = props => <div>
<ModalContext.Consumer>
{modal => <button onClick={() => modal.open('foo')} />}
</ModalContext.Consumer>
</div>;
<ModalContainer>
...deeply nested component
<SomeComponentThatUsesModal />
...
</ModalContainer>
Here's a demo.
Say I have
<component1>
<component2>
<component3>
<component4>
(where component1 has a child component2, component2 has a child component3, component3 has a child component4 )
and say I want to pass something from component1 into component4 . Do I need to pass props down the chain? so component1 -> component2 -> component3 -> component4
?
Please note:
these components are not in the same file. so in component1.js I refer to <component2> and in component2.js I refer to <component3> etc.
You have 2 main options here:
Pass down the props.
Use the context API
With props you also got 2 main options:
You can pass the props implicit
<Parent>
<ChildOne {...props}>
<ChildTwo {...props}>
</ChildTwo>
</ChildOne>
</Parent>
Running snippet for implicit props:
const ChildTwo = props => (
<div>{`Child two says: ${props.myProp}`}</div>
);
const ChildOne = props => (
<div>
<ChildTwo {...props} />
</div>
);
const Parent = props => (
<div>
<ChildOne {...props} />
</div>
);
ReactDOM.render(<Parent myProp="hi there" />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Or do it explicit
<Parent>
<ChildOne propOne={propOne}>
<ChildTwo propOne={propOne}>
</ChildTwo>
</ChildOne>
</Parent>
Running snippet for explicit props:
const ChildTwo = (props) => (
<div>{`Child two says: ${props.myProp}`}</div>
);
const ChildOne = props => (
<div>
<ChildTwo myProp={props.myProp} />
</div>
);
const Parent = props => (
<div>
<ChildOne myProp={props.myProp} />
</div>
);
ReactDOM.render(<Parent myProp="hi there" />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
As for the context API, you can skip levels and "grab" props from grandparents.
This is what react-redux does behind the scenes.
Running example of the context API:
const ChildTwo = (props, context) => (
<div>{`Child two says: ${context.myProp}`}</div>
);
ChildTwo.contextTypes = { myProp: React.PropTypes.string }
const ChildOne = props => (
<div>
<ChildTwo />
</div>
);
class Parent extends React.Component {
getChildContext() {
const { myProp } = this.props;
return { myProp };
}
render() {
return (
<div>
<ChildOne />
</div>
);
}
}
Parent.childContextTypes = {
myProp: React.PropTypes.string
};
ReactDOM.render(<Parent myProp="hi there" />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Note that this example is using react v15, which the syntax for React.PropTypes is changed, Since react v16 PropTypes is no longer part of the react library and it was extracted to another library prop-types.
Also Note, that the docs advise against the usage of the context API:
If you aren’t an experienced React developer, don’t use context. There
is usually a better way to implement functionality just using props
and state.
You can use React's inbuilt Context API, although I wouldn't suggest you rely too much on this because this either could get deprecated or be made into a full stable feature. As of now Facebook warns users with some points in their docs WARNING. Without that hiccup, the API is just wonderful and helps maintain neat code without having to send props all the way to the intended descendant.
CONTEXT API
COMPONENT 1
class Component1 extends React.Component {
getChildContext() {
return {
yourProp: "someValue" // you can also add a function like yourProp: someFunc
};
}
render() {
<Component2 />
}
}
Component1.childContextTypes = {
yourProp: PropTypes.string
};
COMPONENT 2
class Component2 extends React.Component {
render() {
return (
<Component3 />
);
}
}
COMPONENT 3
class Component3 extends React.Component {
render() {
return (
<Component4 />
);
}
}
COMPONENT4
class Component4 extends React.Component {
render() {
return (
<div>
{this.context.yourProp}
</div>
);
}
}
Component4.contextTypes = {
yourProp: PropTypes.string
};
There are quite many strategies if you don't choose to use this.
REDUX
EVENT EMITTER
PASSING PROPS ALL THE WAY TO THE DESCENDANT
Yes with using just React you would need to pass down props through each component, even if the component doesn't use that prop. So in your example control2 & control3 don't care about the prop but need to pass it down. Below is what you would need to do.
<Control1 test={this.state.test}>
<Control2 test={this.props.test}>
<Control3 test={this.props.test}>
<Control4 test={this.props.test} />
</Control3>
</Control2>
</Control1>
This can get cumbersome so this is a case where redux can help.
Is there a way to pass one component into another react component? I want to create a model react component and pass in another react component in order to transclude that content.
Edit: Here is a reactJS codepen illustrating what I'm trying to do. http://codepen.io/aallbrig/pen/bEhjo
HTML
<div id="my-component">
<p>Hi!</p>
</div>
ReactJS
/**#jsx React.DOM*/
var BasicTransclusion = React.createClass({
render: function() {
// Below 'Added title' should be the child content of <p>Hi!</p>
return (
<div>
<p> Added title </p>
{this.props.children}
</div>
)
}
});
React.renderComponent(BasicTransclusion(), document.getElementById('my-component'));
You can use this.props.children to render whatever children the component contains:
const Wrap = ({ children }) => <div>{children}</div>
export default () => <Wrap><h1>Hello word</h1></Wrap>
Note I provided a more in-depth answer here
Runtime wrapper:
It's the most idiomatic way.
const Wrapper = ({children}) => (
<div>
<div>header</div>
<div>{children}</div>
<div>footer</div>
</div>
);
const App = () => <div>Hello</div>;
const WrappedApp = () => (
<Wrapper>
<App/>
</Wrapper>
);
Note that children is a "special prop" in React, and the example above is syntactic sugar and is (almost) equivalent to <Wrapper children={<App/>}/>
Initialization wrapper / HOC
You can use an Higher Order Component (HOC). They have been added to the official doc recently.
// Signature may look fancy but it's just
// a function that takes a component and returns a new component
const wrapHOC = (WrappedComponent) => (props) => (
<div>
<div>header</div>
<div><WrappedComponent {...props}/></div>
<div>footer</div>
</div>
)
const App = () => <div>Hello</div>;
const WrappedApp = wrapHOC(App);
This can lead to (little) better performances because the wrapper component can short-circuit the rendering one step ahead with shouldComponentUpdate, while in the case of a runtime wrapper, the children prop is likely to always be a different ReactElement and cause re-renders even if your components extend PureComponent.
Notice that connect of Redux used to be a runtime wrapper but was changed to an HOC because it permits to avoid useless re-renders if you use the pure option (which is true by default)
You should never call an HOC during the render phase because creating React components can be expensive. You should rather call these wrappers at initialization.
Note that when using functional components like above, the HOC version do not provide any useful optimisation because stateless functional components do not implement shouldComponentUpdate
More explanations here: https://stackoverflow.com/a/31564812/82609
const ParentComponent = (props) => {
return(
{props.childComponent}
//...additional JSX...
)
}
//import component
import MyComponent from //...where ever
//place in var
const myComponent = <MyComponent />
//pass as prop
<ParentComponent childComponent={myComponent} />
You can pass it as a normal prop: foo={<ComponentOne />}
For example:
const ComponentOne = () => <div>Hello world!</div>
const ComponentTwo = () => (
<div>
<div>Hola el mundo!</div>
<ComponentThree foo={<ComponentOne />} />
</div>
)
const ComponentThree = ({ foo }) => <div>{foo}</div>
Facebook recommends stateless component usage
Source: https://web.archive.org/web/20160608001717/http://facebook.github.io/react/docs/reusable-components.html
In an ideal world, most of your components would be stateless
functions because in the future we’ll also be able to make performance
optimizations specific to these components by avoiding unnecessary
checks and memory allocations. This is the recommended pattern, when
possible.
function Label(props){
return <span>{props.label}</span>;
}
function Hello(props){
return <div>{props.label}{props.name}</div>;
}
var hello = Hello({name:"Joe", label:Label({label:"I am "})});
ReactDOM.render(hello,mountNode);
i prefer using React built-in API:
import React, {cloneElement, Component} from "react";
import PropTypes from "prop-types";
export class Test extends Component {
render() {
const {children, wrapper} = this.props;
return (
cloneElement(wrapper, {
...wrapper.props,
children
})
);
}
}
Test.propTypes = {
wrapper: PropTypes.element,
// ... other props
};
Test.defaultProps = {
wrapper: <div/>,
// ... other props
};
then you can replace the wrapper div with what ever you want:
<Test wrapper={<span className="LOL"/>}>
<div>child1</div>
<div>child2</div>
</Test>
You can pass in a component via. the props and render it with interpolation.
var DivWrapper = React.createClass({
render: function() {
return <div>{ this.props.child }</div>;
}
});
You would then pass in a prop called child, which would be a React component.
Late to the game, but here's a powerful HOC pattern for overriding a component by providing it as a prop. It's simple and elegant.
Suppose MyComponent renders a fictional A component but you want to allow for a custom override of A, in this example B, which wraps A in a <div>...</div> and also appends "!" to the text prop:
import A from 'fictional-tooltip';
const MyComponent = props => (
<props.A text="World">Hello</props.A>
);
MyComponent.defaultProps = { A };
const B = props => (
<div><A {...props} text={props.text + '!'}></div>
);
ReactDOM.render(<MyComponent A={B}/>);
Actually, your question is how to write a Higher Order Component (HOC). The main goal of using HOC is preventing copy-pasting. You can write your HOC as a purely functional component or as a class here is an example:
class Child extends Component {
render() {
return (
<div>
Child
</div>
);
}
}
If you want to write your parent component as a class-based component:
class Parent extends Component {
render() {
return (
<div>
{this.props.children}
</div>
);
}
}
If you want to write your parent as a functional component:
const Parent = props => {
return (
<div>
{props.children}
</div>
);
}
Here is an example of a parent List react component and whos props contain a react element. In this case, just a single Link react component is passed in (as seen in the dom render).
class Link extends React.Component {
constructor(props){
super(props);
}
render(){
return (
<div>
<p>{this.props.name}</p>
</div>
);
}
}
class List extends React.Component {
render(){
return(
<div>
{this.props.element}
{this.props.element}
</div>
);
}
}
ReactDOM.render(
<List element = {<Link name = "working"/>}/>,
document.getElementById('root')
);
Let's create a Wrapper Component:
export const Wrapper = (props) => {
return(<>
<Menu />
{props.children}
<Footer />
</>
)
}
You can now enclose your new into an existing structure.
You will enclose the Component in a Route for example:
<Route path="/" element={<Wrapper><ExampleComponent /></Wrapper>} />
You can pass your component as a prop and use the same way you would use a component.
function General(props) {
...
return (<props.substitute a={A} b={B} />);
}
function SpecificA(props) { ... }
function SpecificB(props) { ... }
<General substitute=SpecificA />
<General substitute=SpecificB />
you can pass your react component into another component and emit the function from child
import CustomerFilters;
parent:
const handleFilterChange = (value) => {
console.log(value)
}
<DataGrid
contentName="customer"
fetchFilterComponents = {<CustomerFilters onSelectFilter={handleFilterChange} />}
</DataGrid>
child:
CustomerFilters
return (
<select className="filters-dropdown" onChange={onSelectFilter}>
<option>Select Filter</option>
{customerFilterOptions?.map((filter: any) => {
return <option value={filter.value}>{filter.name}</option>;
})}
</select>
)