Pass a function to a component arrived as '' Props ''. - React - Material UI - reactjs

<SimpleDialog
selectedValue={selectedValue}
open={open}
onClose={handleClose}
title={title}
componentBody={componentBody}
/>
I would like to pass the '' handleclose '' to the component (componentBody), but that component comes to me as '' props '', is there a way to do that?

If you want to pass a component to another component you should use high order components or HOC, and wrap children components like layouts, like below:
function App() {
return (
<div className='App'>
<HOC message={"from App"}>
<ComponentB name='Reza' func={() => alert("alert message")} />
</HOC>
</div>
);
}
const ComponentB = ({ name, func }) => {
return <h1 onClick={func}>name is : {name}</h1>;
};
const HOC = ({ children, message }) => {
return (
<>
{message}
<br />
{children}
</>
);
};
export default App;
In your codebase you can do it like below:
<SimpleDialog
selectedValue={selectedValue}
open={open}
title={title}
>
<componentBody onClose={handleClose}/>
</SimpleDialog>

Related

How can I pass a value from a function to any component in React?

I want to pass a value which I am receiving in a function like this:
const ViewDetails = item => () => {
console.log(item);
toggleModal();
}
I want to pass the item to Modal component like open,onclose which is called in the Main function:
return (
<Layout title="Dashboard" className="container-fluid">
{<Modal open={modalStatus} onClose={() => setModalStatus(false)} />}
<div className="row">
<div className="col-sm-3">
<UserLinks />
</div>
<div className="col-sm-9">
<UserInfo />
{orders ? <PurchaseHistory /> : ""}
</div>
</div>
</Layout>
)
I am expecting to have something like this:
{<Modal open={modalStatus} onClose={() => setModalStatus(false)} ***item={item}***/>}
so that I can use the values inside item in Modal component.
I would like to add more to #GODWIN GODWIN comment in regards context API, by providing a very simple example along with the React docs about Context hook
Generally in practice people tend to wrap providers at App.js, for the sake of simplicity I am going to wrap at index.js file.
src/index.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App'
import { ModalProvider } from './context/ModalContext'
ReactDOM.createRoot(
document.querySelector('#root')
).render(
/**
* #dev Note everything inside ModalPrivder has access
* to the values provided, such as open, setOpen
*/
<ModalProvider>
<App />
</ModalProvider>
)
src/context/ModalContext.jsx
import React, {useState, createContext, useContext } from 'react'
/**
* #dev inside your createContext object you can pass in
* default values that will be passed in value at provider
*/
export const ModalContext = createContext({
open: false
})
/**
* #dev your provider will enable you to access value all your
* children components. NOTE it will not be able to access your
* parent components.
*/
export function ModalProvider(props) {
const [open, setOpen] = useState(false)
return (
<ModalContext.Provider value={{ open, setOpen }}>
{props.children}
</ModalContext.Provider>
)
}
src/components/Modal.jsx
import { useContext } from 'react'
function Modal(props) {
const { open, setOpen } = useContext(ModalContext)
return (
<>
{ open ?
(<div>
<p>test</p>
<>{props.children}</>
<button onClick={() => setOpen(false)}>Close Close</button>
</div>) :
(<button onClick={() => setOpen(true)}>Open Modal</button>)
}
</>
)
}
export default Modal
src/App.jsx
function App(props) {
return (
<div className='App'>
<h1>Hello React.</h1>
<h2>Start editing to see some magic happen!</h2>
<Modal>
<p> You see content here</p>
</Modal>
</div>
);
}
export default App
I hope this give you a good direction on how to use React's context hook, please note that this is a very basic source code, to understand how props.children works and context hook.
You can try this:
import React from "react";
function Eexample() {
const ViewDetails = (item) => () => {
console.log(item);
toggleModal();
return (
<Modal item={item} /> //This is passing item into the Modal component
)
};
return <div>
{ViewDetails} {/*This returns the function viewDetails*/}
</div>;
}
export default Eexample;
For your Modal component:
function Modal({ item }) { // with this distructuring, you can use the item inside the Modal component
return (
<Layout title="Dashboard" className="container-fluid">
{<Modal open={modalStatus} onClose={() => setModalStatus(false)} />}
<div className="row">
<div className="col-sm-3">
<UserLinks />
</div>
<div className="col-sm-9">
<UserInfo />
{orders ? <PurchaseHistory /> : ""}
</div>
</div>
</Layout>
)
}
Or Consider using context API, it enables you to dispatch the item to your reducer.js file and pull it in your Modal component using StateProvider.js file.
You have to take state for this item. When viewDetails function triggered from inside this function you can set this state with this item afte can be pass this state as a props any component

How to pass a value for useState hook from another component in ReactJS?

I have two components:
Parent.js
import { useState } from "react";
function Parent() {
const [showHideContent, setShowHideContent] = useState("none");
return (
<div style={{ display: showHideContent }}>
Some content here...
</div>
);
}
Child.js
function Child() {
return (
<button>
Show/Hide Content
</button>
);
}
I want to pass two values none and block (one value at a time) through setShowHideContent of Parent component using Show/Hide Content button of Child component.
How to do this?
NOTE: These two components are saved in the same folder but in two different files.
These two component are rendered by App.js.
<Route path="/content">
<Menu /> {/* rendering in LEFT */}
<div className="content-flexbox">
<Parent /> {/* rendering in CENTER */}
<Child /> {/* rendering in RIGHT */}
</div>
<Footer /> {/* rendering in BOTTOM */}
</Route>
It seems like you want the Child component to simply toggle the display value of some content in the Parent component.
As you've defined them though they are not parent-child, but rather they are siblings. As such if they need to share state/behavior, then the solution is to lift state up to a common ancestor, App in this case.
<Route path="/content">
<Menu />
<div className="content-flexbox">
<Parent /> // <-- siblings
<Child /> // <-- siblings
</div>
<Footer />
</Route>
See: Lifting State Up
Move the showHideContent state and updater into the parent App component, pass down the showHideContent state to Parent and the toggleVisibility callback to the Child.
function Parent({ showHideContent }) {
return <div style={{ display: showHideContent }}>Some content here...</div>;
}
function Child({ onClick }) {
return (
<button type="button" onClick={onClick}>
Show/Hide Content
</button>
);
}
export default function App() {
const [showHideContent, setShowHideContent] = React.useState("none");
const toggleVisibility = () =>
setShowHideContent((value) => (value === "none" ? "block" : "none"));
return (
...
<Route path="/content">
<Menu />
<div className="content-flexbox">
<Parent showHideContent={showHideContent} />
<Child onClick={toggleVisibility} />
</div>
<Footer />
</Route>
...
);
}
You can simply pass values as prop to child component.
Call your child component inside parent component and pass value
import { useState } from "react";
import Child from "//your path";
function Parent() {
const [showHideContent, setShowHideContent] = useState("none");
return (
<div style={{ display: showHideContent }}>
<Child showHide={showHideContent}/>
</div>
);
}
Now in your child component
function Child({showHide}) {
return (
<button>
{showHide}
Show/Hide Content
</button>
);
}
Include your Child component in your Parent component and pass hooks as props
import { useState } from "react";
// import the child component
function Parent() {
const [showHideContent, setShowHideContent] = useState("none");
return (
<div style={{ display: showHideContent }}>
Some content here...
<Child showHideContent={showHideContent}/>
</div>
);
}
And use them in your child components
function Child({showHideContent}) {
return (
<button>
{showHideContent}
Show/Hide Content
</button>
);
}
Another way of doing the same is by using Context API:
https://reactjs.org/docs/hooks-reference.html#usecontext
You can pass an inline function as prop from parent to child like this.
function Parent(){
const [showHideContent, setShowHideContent] = useState("none");
return (
<Child onButtonClicked={(toValue) => setShowHideContent(toValue)} />
)
}
function Child({ onButtonClicked }) {
return (
<button onClick={onButtonClicked} >
Show/Hide Content
</button>
);
}
Pass down exact state modifier with same name
function Parent(){
const [showHideContent, setShowHideContent] = useState("none");
return (
<Child setShowHideContent={setShowHideContent} />
)
}
//or with prop speading
function Parent(){
const [showHideContent, setShowHideContent] = useState("none");
return (
<Child {...{setShowHideContent}} />
)
}

Formik in React Container Pattern

I am using React Container Pattern for a project with Formik. If I want to pass some props from "Container component" to "Presentational component" how can I catch those props in Presentational Component?
//CONTAINER COMPONENT
render() {
return (
<CreateColorContainer
key="CreateColor"
name="Add Color"
{...this.state}
/>
);
}
//PRESENTATIONAL COMPONENT
<Formik
initialValues={}
validationSchema={}
onSubmit={(fields) => {}}
>
{(props) => {
const { touched, errors, setFieldValue } = props;
return (
<div className="page-wrapper">
//Props i want to use here
</div>
);
}}
</Formik>

react stateless component with onClick issue

I have a stateless component and i want to be able to click on the image and redirect it to a new page.
The issue that i am having is that i cannot get onClick to work correctly.
I was trying to write a function within the onClick = {this.ProjectSelected} but this will not work.
Do i have to pass a function (onClick) from the parent to child component? If so how do i do that?
I am able to log the project id to the console.
Thanks for the help.
const projectListTemplates = (props) => {
const { classes } = props;
return (
<div>
<div className={classes.root}>
<GridList className={classes.gridList}>
<GridListTile key="Subheader" cols={2} style={{ height: 'auto' }}>
<Subheader component="div">Projects</Subheader>
</GridListTile>
{props.data.map(item => (
<GridListTile key={item.image}>
<img src="./images/Project/1.jpg" alt={item.title} />
<GridListTileBar
title={item.title}
subtitle={<span> {item.name}</span>}
onClick={()=>console.log(`this project was clicked ${item.id}`)}
>
</GridListTileBar>
/>
<ProgressBar now={60} />
</GridListTile>
))}
</GridList>
</div>
</div>
);
In stateless component we are not defining any local property like state or methods. We have only props and rendering data based on props. We have only props events to trigger. So we have to pass a event function from parent component in order to handle click event. If you want to keep click event locally, convert component to stateful (Class).
Stateless
const ProjectListComponent = (props) => {
const { onClick } = props
return (
<button onClick={onClick}>Click me</button>
)
}
class AppComponent extends Component {
handleClick() {
console.log('clicked')
}
render() {
return (
<ProjectListComponent onClick={this.handleClick} />
)
}
}
Stateful
class ProjectListComponent extends Component {
handleClick() {
console.log('clicked')
}
render() {
return (
<button onClick={this.handleClick}>Click me</button>
)
}
}

Storing component into a variable and reuse it

Ok i got components imported as
import Payment from './pages/payment';
import Chat from './pages/chat';
Now I am using Drawer component and using it together with Navigator my renderScene become something like this
if( route.id == 'payment'){
return <Drawer xx={} yy={} and a lot more >
<Payment navigator={navigator} />
</Drawer>
}
if(route.id == 'chat'){
return <Drawer xx={} yy={} and a lot more >
<Chat navigator={navigator} />
</Drawer>
}
Those lengthy Drawer code are being used again and again. I want to store that <Payment navigator={navigator} > or the other into a variable and then return that with Drawer only once.
How can i store it and return it with Drawer?
Thanks
Not sure if you are asking this but what about something like:
const routes = {
payment: Payment,
chat: Chat
...
}
And then, just:
const Scene = routes[route.id];
return (
<Drawer>
<Scene navigator={navigator}/>
</Drawer>
)
Here you have 3 options:
// 1. Group the drawer props in an object
const drawerProps = {
xx: ...,
yy: ...
};
<Drawer {...drawerProps}>
<Chat navigator={navigator} />
</Drawer>
// 2. Define a wrapper object that populates the common Drawer props
const CustomDrawer = ({ children }) => (
<Drawer xx={} yy={} and a lot more>
{children}
</Drawer>
);
// 3. Define a wrapper object that populates the common Drawer props with default props. (Can be
// overriden.)
const CustomDrawer = ({
xx='XX',
yy='YY',
children
}) => (
<Drawer xx={xx} yy={yy} and a lot more>
{children}
</Drawer>
);
EDIT: I missunderstood your question, for storing the inner part you just have to assign it to a varible and use it.
const routes = {
chat: <Chat navigator={navigator} />,
payment: <Payment navigator={navigator} />,
}
<Drawer {...drawerProps}>
{ routes[route.id] }
</Drawer>
I propose this solution with a React hook (React v16.8+).
The useMemo returns a component according to the route agument passed to the switch. The useMemo is updated each time one of the internal variables (passed as a second argument as route) is updated.
import React, { useState, useMemo } from 'react';
export default function App ({
route,
navigator
}) {
const [route, setRoute] = useState('payment');
const mainContent = useMemo(() => {
return () => {
switch (route) {
case 'payment':
return (
<Payment navigator={navigator} />
);
case 'chat':
return (
<Chat navigator={navigator} />
);
}
}
}, [route, navigator])
return (
<Drawer xx={} yy={} and a lot more >
{ mainContent() }
</Drawer>
);
}

Resources