Let say I have this:
// Parent component:
export default function() {
return (
<React.Fragment>
<Toolbar slot="fixed" bottom>
This will be fixed to bottom of page
{order.name}
</Toolbar>
</React.Fragment>
)
}
I want to make the parent component with the least of code possible - shared
into small cuts, so the toolbar will be in a child component so it will be
looking just like this:
// Parent component:
export default function() {
return (
<React.Fragment>
<MyAwesomeToolbar order={order} />
</React.Fragment>
)
}
// MyAwesomeComponent:
export default function(self) {
let { order } = self.props
return (
<Toolbar slot="fixed" bottom>
This will be fixed to bottom of page
{order.name}
</Toolbar>
)
}
In the first example - when the toolbar is actually hard coded in the parent component,
everything works good - the toolbar lays in the bottom of the page.
But when doing it the second way, the toolbar lays just not in the bottom but
float in the middle of the page without the fixed attribute as well.
I have tried to make a component using class, or just a simple render file (.JSX).
Both didn't work.
How to render child component with the same properties and styles as it was layed in the parent?
Does it work if you move the <React.Fragment />?
// Parent component:
export default function() {
return (
<MyAwesomeToolbar order={order} />
);
}
// MyAwesomeComponent:
export default function(self) {
let { order } = self.props;
return (
<React.Fragment>
<Toolbar slot="fixed" bottom>
This will be fixed to bottom of page
{order.name}
</Toolbar>
</React.Fragment>
);
}
Related
function DatTable() {
return (
<DataTable
theme="dark"
columns={columns}
selectableRows
data={FakeData}
/>
);
};
I've called this component from another file in a dashboard
</Box>
<DatTable></DatTable>
</Box>
Everything works properly if I change the properties in the original function. What I'm trying to achieve is set a useTheme hook for the component and for that I want to edit the theme inside of the dashboard like so :
</Box>
<DatTable
theme="dark"
></DatTable>
</Box>
I've tried changing the properties inside of the dashboard component but it has no effects. I'm also unsure how to turn regular components into React components since the webpage goes white and breaks if I try it that way.
// default data
let columns={};
let data={}
function DatTable(theme="dark", columns=columns, selectableRows='somedefaultdata',data=FakeData) {
return (
<DataTable
theme=theme
columns={columns}
selectableRows
data={FakeData}
/>
);
};
Now
<DatTable
theme="white"
/>
If you this now:
you don't need to send props at all.
If you send props those props will overwrite those default values
Since you pass a theme prop to <DatTable> you need to extract it and then use it as a prop again in <DataTable>
function DatTable({theme}) {
return (
<DataTable
theme={theme}
columns={columns}
selectableRows
data={FakeData}
/>
);
};
after getting all mixed up with state, i am now trying to restructure my app in a way that might be more reflective of best practices (not sure if this is the way, advice is welcome.)
so, i have my main page, which holds 3 states: viewer,buyside,sellside
there are also three different components, one for each of those states.
i want to be able to pass the props down from the main page, through those components, to their children (i've read this is the best approach??)
main page:
//we have 3 states for the website: viewer,buyside customer, sellside customer
const [visitorType, setVisitorType] = useState('viewer');
if (visitorType == 'viewer') {
return(
<div>
<Viewer visitortype='viewer' setvisitor={()=>setVisitorType()}/>
</div>
)}
else if (visitorType =='buyside') {
return(
<div>
<Buyside visitortype='buyside' setvisitor={()=>setVisitorType()}/>
</div>
)}
else if (visitorType =='sellside') {
return(
<div>
<Sellside visitortype='sellside' setvisitor={()=>setVisitorType()}/>
</div>
)}
};
what is the best way to pass down the main page props, so that i can bring them down to any grandchildren, along with the child props?
the viewer component -UPDATED-:
const MainView = (props) => {
return(
<>
<Navbar mainprops={{props}}/>
</>
)
};
export default MainView
i was previously just passing them individually, but realized it might be better to do so as one object...
UPDATE: point taken on the syntax, but i'm wondering how i can best pass the objects
nav component (grandchild)
const Navbar = (props) => {
const {mainprops} = props.mainprops;
if (mainprops.visitortype == 'viewer') {
return(
<>
<h1>viewer navbar</h1>
</>
)}
else if (mainprops.visitortype =='buyside') {
return(
<>
<h1>buyside navbar</h1>
</>
)}
else if (mainprops.visitortype =='sellside') {
return(
<>
<h1>sellside navbar</h1>
</>
)}
};
export default Navbar;
UPDATE 2 - this works, but not sure if it is the correct way, are these still considered object literals??
viewer component:
const MainView = (props) => {
const mainprops = {...props}
return(
<>
<Navbar mainprops={mainprops}/>
</>
)
};
export default MainView
navbar component
const Navbar = (props) => {
const mainprops = {...props.mainprops};
if (mainprops.visitortype == 'viewer') {
return(
<>
<h1>viewer navbar</h1>
</>
)}
else if (mainprops.visitortype =='buyside') {
return(
<>
<h1>buyside navbar</h1>
</>
)}
else if (mainprops.visitortype =='sellside') {
return(
<>
<h1>sellside navbar</h1>
</>
)}
};
export default Navbar;
if this is correct, then is this what #amir meant?
First there are certain rules for passing props:
You never ever pass literal object as props since it will not be the same every re-render and will cause the child component to re-render too (without any new info)
You don't need to do that
<Viewer visitortype='viewer' setvisitor={()=>setVisitorType()}/>
You can:
<Viewer visitortype='viewer' setvisitor={setVisitorType}/>
since it comes from useState react make sure the setVisitorType keeps the same reference
And now for you error, you almost correct you just did a js syntax error
you should write it like this:
const MainView = (props) => {
return(
<>
<Navbar mainobj={{
visitortype:props.visitortype,
setvisitor:props.setvisitor
}}
/>
</>
)
};
export default MainView
But again you never send literal object as props
I would keep it inside a ref or state (depend if the visitor state will be change)
I have difficulties trying to pass props to this.props.children. I know there's a few similar posts, however, I believe I have tried most of the accepted solutions, and it's still not behaving and expected. So, I guess I'm missing something vital.
The general idea is this: I have a <NavBar> component that I would like to wrap around my pages as shown below. I'd like for the wrapped page to accept props passed down from the <NavBar> component.
<NavBar>
<Container>
<Grid container>
<Grid item>
...
</Grid>
</Grid>
</Container>
</NavBar>
Currently my <NavBar> is defined as such:
class NavBar extends React.Component<React.PropsWithChildren<NavBarProps>, NavBarState>
So, my component has a prop children?: React.ReactNode. In my render() method I am rendering an <AppBar> (from Material UI library) underneath which I display the children similar as such:
render() {
const {children} = this.props;
return(
<>
<AppBar>...</AppBar>
{children}
</>
)
}
Some attempts I've had:
render() {
const children = React.cloneElement(this.props.children as React.ReactElement, {
test: "test"
});
return(
<>
<AppBar>...</AppBar>
{children}
</>
)
}
What I expect: In this case, I would like to be able to access the test props from any page wrapped within <NavBar> like this.props.test
I also tried:
const children = React.Children.map(this.props.children as React.ReactElement, (child) =>
React.cloneElement(child, { test: "test" })
);
&
const children = React.Children.map<ReactNode, ReactNode>(this.props.children, (child) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { test: "test" });
}
});
Result so far: I've been unsuccessful and trying to access this.props.test from my page returns undefined.
I don't see anything wrong with your third attempt. Here is a working example using that method. Notice unlike your second attempt, you do need to return from the map.
function Test() {
return (
<Parent>
<Child />
</Parent>
);
}
class Parent extends React.Component {
render() {
const children = React.Children.map(this.props.children, (child) => {
return React.cloneElement(child, {test: 'test'});
});
return (
<div>
<h3>Parent</h3>
{children}
</div>
);
}
}
class Child extends React.Component {
render() {
return (
<div>
<h3>Child</h3>
Test Prop: {this.props.test}
</div>
);
}
}
ReactDOM.render(<Test/>, 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"/>
Created codesandbox to show issue:
https://codesandbox.io/s/agitated-https-2xjs2?fontsize=14&hidenavigation=1&theme=dark
I'm wanting a Tooltip to show whenever I'm hovering over a card. I need to pass in a value from the OverlayTrigger to the Tooltip component. With the following code, nothing is showing when hovering over a card:
Character.js:
import React from 'react'
import { Card, OverlayTrigger } from 'react-bootstrap'
import Infott from '../components/Infott'
const Character = ({ character }) => {
return (
<OverlayTrigger
trigger='hover'
placement='bottom'
overlay={<Infott test={'Test'} />}
>
<Card className='my-3 py-3 rounded'>
<a href={`/character/${character._id}`}>
<Card.Img src={character.image} />
</a>
</Card>
</OverlayTrigger>
)
}
export default Character
Infott.js:
import React from 'react'
import { Tooltip } from 'react-bootstrap'
const Infott = ({ test }) => {
return (
<Tooltip id='character-tooltip' placement='bottom'>
<strong>{test}</strong>
</Tooltip>
)
}
export default Infott
If I add className=show to the Tooltip component, it will show and the test value is passed, but it's no longer placed next to the card but rather the bottom left of the webpage. My guess is the OverlayTrigger and Tooltip are not on the same page.
I can get the Tooltip placement showing and in the correct placement if I change overlay to overlay={Infott} and then change my Tooltip component to
const Infott = (props) => {
return (
<Tooltip id='character-tooltip' placement='bottom' {...props}>
<strong>{test}</strong>
</Tooltip>
)
}
But then I'm not able to pass the test value that I need.
OverlayTrigger seems to use ref to the target Tooltip for some actions as well as some properties that it injects so in order to work properly you must forward a ref from your custom component to the target Tooltip you have wrapped inside.
So the correct solution for having your Tooltip wrapped in a custom component should be something like:
const Infott = React.forwardRef(({test, ...props}, ref) => {
return (
<Tooltip id='character-tooltip' ref={ref} placement='bottom' {...props}>
<strong>{test}</strong>
</Tooltip>
);
});
Here is what I am using:
<Modal
visible = {this.props.visible}
animationType="slide"
transparent
onRequestClose={() => {}} >
<TextInput
style = {styles.inputBox}
ref = {this.props.destinatinon} />
</Modal>
and in the Container
<ExampleModal
destination = {this.state.destination} >
</ExampleModal>
I don't know how to pass data from Modal to Parent Component. Any kind of Tutorial or link is fine. Thanks in Advance.
Let's assume that your Modal is filed separately in /components/MyModal to generalize things.
You can make your Modal call a function that you passed by props every time input text is changed. Here's a simple callback logic you can use.
Avoid using refs as much as you can.
import MyModal from '../components/MyModal';
...
class Home extends Component {
onInputChanged = (changedText) => {
console.log('This is the changed text: ', changedText);
}
render() {
return (
<View>
...
<MyModal onInputChanged={this.onInputChanged} .../>
</View>
)
}
}
// components folder
class MyModal extends Component {
render() {
return (
<Modal
visible = {this.props.visible}
animationType="slide"
transparent
onRequestClose={() => {}} >
<TextInput
style = {styles.inputBox}
onChangeText={(changedText) => this.props.onInputChanged(changedText)} />
</Modal>
)
}
}
Side Note: You can define MyModal stateless to make things a bit cleaner.