ReactJS, passing prop from parent to child component? - javascript

I have a bunch of components that require the same prop, and going through them individually to add the JSX is cumbersome, can I create a piece of JSX in the parent that will be passed to these child components as a prop?
Here's basically what I want to do:
function App(props) {
/*not part of the actual code, but I want to
pass this h1 tag into the bottom components as a prop*/
<h1>{props.heading}</h1>
<Home heading="Home"/>
<AboutMe heading="About Me"/>
<Contact heading="Contact"/>
}
I know the code above isn't how you're supposed to do it, but is there a way I can accomplish that functionality?

Yes, that's possible. Just assign your JSX component to a variable and pass that variable as a prop. You have the right idea.
For example:
var customHeader = <h1>Here's a custom component</h1>
You can also set customHeader to a React component such as: var customHeader = <CustomHeader />
You can pass through <MyComponent header={customHeader}/> and in your render function of MyComponent page, you can simply use {this.props.header} to load your component. This can be repeated for any number of components.
Edit based on comments. In that case, I would wrap the component in a function. For example:
getCustomHeader = (title) => {
return <MyHeader
headerTitle={title}
/>
}
Now, in your render function, you can call getCustomHeader.
render() {
return <div>
<MyComponent1 header={this.getCustomHeader("Title A")} />
<MyComponent2 header={this.getCustomHeader("Title B")} />
</div>
}

Related

vue 3 access props passed from parent component that are not defined in child component

hope everything is okay.
i am used to react.js but when i try vue things were a bit different
in react it's very simple accessing props passed from parent in the child component
but in vue i must define each prop to use it.
so i was just wondering if it's possible to pass any prop and use it in the child component without defining it
in react i can do that
// parent component
const Parent = () => {
return (
<Child anyprop="propvalue" />
)
}
const Child = (props) => {
return (
<p>{JSON.stringify(props)}</p>
)
}
and that would work
in vue i can only use props if i define it like this
//parent
<template>
<Child anyprop="value" anotherprop="value"></Child>
</template>
<script setup>
const props = defineProps({
anyprop: String
})
//child
<template>
<p>{{props}}</p>
</template>
<script setup>
const props = defineProps({
anyprop: String
})
</script>
if i do that in vue i can only see "anyprop" not the "anotherprop" i must define it in the define props block to use it
any ideas what can i do to achieve something like what react.js offers
All data that isn't defined in props goes to attributes. Despite the name, they aren't HTML attributes and can have non-string values.
In a template they are available as $attrs:
<Child :anyprop="$attrs.anyprop" anotherprop="value"/>
A more common case is to pass all attributes instead of enumerating them, this is a counterpart to React {...rest}:
<Child v-bind="$attrs" anotherprop="value"/>
This may be not needed for root element like Child because attribute fallthrough is done by default, otherwise inheritAttrs: false should be used.
This requires Child to have anyprop prop declared.
In a script, attributes are available as context.attrs in setup function and useAttrs in script setup, they can be used to compute props for nested elements.

How to pass props down to child component in React

So in my main component, I send props to a child component like this:
<div className={styles.navBar}>
<MasterNavBar color={false} scrollChange={true} />
</div>
MasterNavBar gets access to the props correctly, but I need MasterNavBar to pass those props to a child component called NavBar, which I currently do like this:
<NavBar props />
However, when I do this, the props are not accessible in my NavBar component file. For example, in NavBar, doing props.color to get my color prop returns undefined. So, am I passing my props incorrectly, or am I missing something else?
As Antonio Pantano said, you can pass the whole props to the <NavBar {...props}/> component, but this is a bad practice way. This article explained why it is a bad practice way. So you can pass the MasterNavBar props to its child in these two ways:
const MasterNavBar = (props) => {
/*
rest of your code
*/
return <NavBar color={props.color} scrollChange={props.scrollChange}/>
}
or
const MasterNavBar = ({color, scrollChange}) => {
/*
rest of your code
*/
return <NavBar color={color} scrollChange={scrollChange}/>
}
You can change the name of NavBar props as you wish, and you access them in the NavBar component by these names.
That's depend on which props NavBar is expecting. If you don't care about typing (either with typescript or react PropTypes) you can simply do like this:
<NavBar {...props} />
However this is not the best approach and can lead to performance issues.

Which way is better for sending functions references to react components?

I'm trying to send function reference to imported component. So it's better I use ref attribute or props ?
I want to find an optimum and standard method.
<MyComponent ref="ListView" />
Or this method:
<MyComponent show="this.showModal" hide="this.hideModal" />
There wouldn't be an effect if you pass functions as a string (like "this.showModal").
Pass them down in curly braces:
<MyComponent show={this.showModal} hide={this.hideModal} />
Refs purpose is to manipulate DOM directly, not to pass something to the component. For example, you may want to manipulate DOM with jQuery
We don't use refs for event handling it is preferable to pass handlers as props to child component using JSX sytax with {} braces.
You want to send eventhandler to child component from parent if i understand your question correctly?
parent.js
class ParentComponent extends Component {
handler = () => {
console.log("handler click">
}
render() {
return (
<div>
<Child handler={this.handler} />
</div>
);
}
}
child.js
const Child = ({ handler }) => (
<Button onClick={handler} />
)
EDIT:
I understood your question, if you have a lot of method you can use ...props but also you can pass props as separated methods.
I think you're referring to the differences between controlled and uncontrolled components :
uncontrolled-
https://reactjs.org/docs/uncontrolled-components.html
controlled-
https://reactjs.org/docs/forms.html
The answer for that is depending on your component "logic", if you want to controll it by the DOM(using refs) or by the component itself.

React Render with Hoc

So I am following some tutorial and I am confused regarding how things render when using HOC
So firstly, I guess props flow from parent to child and is one directional?
Here we created two HOC, The Aux and withclass
The Aux doesn't do anything special besides passing props.children
const aux = (props) => props.children;
export default aux;
The withClass HOC function takes two parameter App and className..
const withClass = (WrappedComponent, className) => {
return class extends Component {
render () {
return (
<div className={className}>
<WrappedComponent {...this.props} />
</div>
)
}
}
And our App.js which is passed as an argument looks like this
import React, { PureComponent } from 'react';
import classes from './App.css';
import Persons from '../components/Persons/Persons';
import Cockpit from '../components/Cockpit/Cockpit';
import Aux from '../hoc/Aux';
import withClass from '../hoc/withClass';
class App extends PureComponent {
//something
render () {
if ( this.state.showPersons ) {
persons = <Persons
persons={this.state.persons}
clicked={this.deletePersonHandler}
changed={this.nameChangedHandler} />;
}
return (
<Aux>
<button onClick={() => { this.setState( { showPersons: true } ) }}>Show Persons</button>
<Cockpit
appTitle={this.props.title}
showPersons={this.state.showPersons}
persons={this.state.persons}
clicked={this.togglePersonsHandler} />
{persons}
</Aux>
);
}
}
export default withClass( App, classes.App );
[Question] So based on the above code if someone can please explain what exactly happens, the way things execute and render?
Secondly, We used {...this.props} in our withClass HOC because according to the instructor they are wrapped and hence our other component, even though they receive prop they can't pass them. Can someone explain this with an example? Also {...this.props} creates copy of all the props? and shouldn't it be like <WrappedComponent = {...this.props} /> instead of <WrappedComponent {...this.props} />
First of all, what is a HOC?
A HOC is a Higher-order component. This means it is a function that takes as its first argument a component and then returns a component.
From this definition you can immediately see that:
withClass is an HOC
Aux is not an HOC
Aux is a functional component. Classic React components are created by defining a class that inherits from React.Component. A newer, simpler way of defining components is to create functions that simply accept props as the first parameter and return what should be rendered.
So based on the above code if someone can please explain what exactly happens, the way things execute and render?
Well, let's look at App just as a component. We have withClass and App and you're exporting withClass(App, classes.App). What would it look like if, instead of using an HOC we used a functional component? It'd look like this:
const AppWithClass = props =>
<div className={classes.App}>
<App/>
</div>
In this case, no props are passed to App. So with this use-case, there is no need to pass props through by writing {...props}. And you'd then simply export AppWithClass.
But usually you write HOCs to be reusable. In that case, you don't know if the component that will be passed to your HOC will receive props or not. For that reason, you want the component you create to take any props passed to it and to pass them through to the wrapped component.
Let's say you have a Button component that takes a parameter colour. You'd typically use it like this:
<Button colour="red"/>
But you want to wrap it with a div and add a class to that div. So you use withClass as follows:
const ButtonWithClass = withClass(Button, "button-class");
Now you can use Button as follows:
<ButtonWithClass colour="red"/>
And really what you'll get is:
<div className="button-class">
<Button colour="red"/>
</div>
If you did not write {...this.props} when rendering WrappedComponent in your withClass HOC, then colour would not get passed through to Button. In your HOC, WrappedComponent is equal to Button in the above case.
The syntax {...this.props} is a combination of the Object literal spread syntax and JSX's own behaviour. The Object spread syntax used in this way means the keys of the given object will become the prop names and the values will become their respective values. So when you write {...{ colour: 'red' }} you're asking JSX to get props from an object that you define inline.
To continue with the above example:
<ButtonWithClass colour="red"/>
Inside withClass this becomes equivalent to:
const WrappedComponent = Button;
return <WrappedComponent {...this.props}/>;
And here this.props equals { colour: 'red' }. So the above becomes:
const WrappedComponent = Button;
return <WrappedComponent {...{ colour: 'red' }}/>;
Which then becomes:
const WrappedComponent = Button;
return <WrappedComponent colour="red"/>;
I hope that helps!

Communicating between nested child components in React.js

It won't take you long to realise that I am probably out of my depth here. I am not only new to React.js but also to ES6 and so please be gentle with your answers...
Here goes.
I am using a component to build a form input:
const Input = (props) => {
return(
<input ... />
)
}
I have a component which I use to construct HTML around any of the basic form elements that I give it.
const InputWrap = (props) => {
return(
<div class="input-wrap" ...>
{children}
</div>
)
}
Which allows me to do something like this...
const Input = (props) => {
return(
<InputWrap>
<input ... />
</InputWrap>
)
}
What I would like to do is to add a character counting component to the mix:
const InputWrap = (props) => {
return(
<div class="input-wrap" ... >
{children} // which is the HTML input
{props.maxValue && <CharCounter />}
</div>
)
}
So here is my problem...
The <CharCounter /> needs to be notified of any changes happening to the <input /> and update it's internal state.
The <input /> and the <CharCounter /> are siblings and children of the <InputWrap /> and so, from what I can gather, I need a method inside <InputWrap /> which ties an onChange of the <input /> and some method that will update the state within the <CharCount /> component.
I am at a loss as to how I go about adding a callback as the <input onChange={doSomething} /> is in the form {children} by the time it comes in contact with the <CharCount /> once inside the <InputWrap />...
Where am I going wrong here? I'm starting to think it was way back at the beginning...
There are two typical ways of communication between siblings:
You use the InputWrapper as an DataContainer
You use a Data Flow library like flux or redux (which is a lot more complex, especially for this case)
For the 1. you need, as you correctly noticed, an onChange handler for the input component, which is a function defined in the Component and which is passed to the input. If your input component is an own component and not the native component you will need to pass the onChange prop to the native input.
The function in the Component takes the input, counts the chars and sets an internal state variable with setState({ charCount: #CountValue#}). And then you can pass the state variable to the CharCount Component with
One Important thing to mention: You are using stateless components and therefore you will need to change your InputWrap to a normal react component
class InputWrap extends React.Component {
...
}
Hope this will give you the right direction.
Another excellent solution that is like redux but has a different architecture and api is https://github.com/mobxjs/mobx-react.
You can use the inject HOC to inject shared state to any react component in your application.

Categories

Resources