Unable to access the props directly in Child Component - javascript

I have stored the data in a file (details.js) as a JavaScript Object, then I'm trying to pass it as a prop from MainComponent to ChildComponent. Well the prop is accessible in ChildComponent but I could access it with props.ChildDetails[0].name instead of props.name directly as shown in the Official documentation
What am i missing?
details.js
export const DETAILS=[
{
id:0,
profile:'/assests/images/john.png',
name:'John Doe',
}
]
MainComponent.js
import React,{useState} from 'react';
import Child from './ChildComponent';
import {DETAILS} from '../Shared/details';
function MainComponent(){
return(
<>
<Child ChildDetails={DETAILS}/>
</>
);
}
export default MainComponent;
ChildComponent.js
import React from 'react';
function ChildComponent(props){
console.log(props.name) //Output:undefined
console.log(props.ChildDetails[0].name) //Output:John Doe
return(
<div></div>
);
}
export default ChildComponent;

Because Details is object.
Try something like:
function ChildComponent({ ChildDetails }){
const { name } = ChildDetails[0]
...
}
That's not even React. That's JavaScript
Edit. Oops. People said that's an array. I thought it's just an object. Fixed code a bit

here is where you passed the object
<Child ChildDetails={DETAILS}/>
and here is how you tried to use it
console.log(props.name) //Output:undefined
since you defined the name as ChildDetails there is no such thing as props.name instead you must say
console.log(props.ChildDetails)
and if you want to get access to an name you should declare the index if not react does not know which index you want to use, so as you did before
props.ChildDetails[0].name

Related

How a React component is able to access props not passed to that component?

I've following three components and passing Hello to Parent.js component but Child.js is also able to access it. So could anyone please explain me the reason behind that ?
App.js
import Parent from "./Parent";
export default function App() {
return (
<div>
<Parent
test="Hello"
/>
</div>
);
}
Parent.js
import Child from "./Child";
export default Child;
Child.js
const Child = ({ test }) => {
return (
<div>
<h1>From Child Component: {test}</h1>
</div>
);
};
export default Child;
This code in Parent.js:
import Child from "./Child";
export default Child;
just re-exports Child as the default export from Parent.js. It doesn't create a new component, it just provides a second way to use the same component, as though you did this:
const Parent = Child;
So when you use Parent, you're actually using the Child component in Child.js.
If you want a separate component, you need to actually create a separate function or class, for example:
import Child from "./Child";
export default function Parent() {
return <Child />;
}
If you had that in Parent.js, Child wouldn't see test because Parent doesn't pass test to it. You could pass it on, of course:
import Child from "./Child";
export default function Parent({test}) {
return <Child test={test} />;
}
How a React component is able to access props not passed to that component?
It can't. Your code is passing test to Child (via the other name you've given it, Parent).
probably because the parent component is export child > you are just aliasing
Your Parent component is the same as the Child component. They have the same definition

How React HOC function knows the props of a Component that put into it as a parameter

I try to understand how React HOCs work. The following code that will be written bellow WORKS, but I cannot understand WHY it works:
const MyHOC = (WrappedComponent) => {
return (props) => { //these props are the props of a WrappedComponent
return (
<div style={{color: "red", fontSize: "100px"}}>
<WrappedComponent {...props}/>
</div>
)
}
}
export default MyHOC
After that, I use my hoc here:
import MyHOC from "../HOC/MyHOC" //hoc
const SomeStuff = (props) => {
return (
<div>
Hello world!!!
{
props.data.map(item => {
return <div>{item}</div>
})
}
</div>
)
}
//our component wrapped with a hoc
export default MyHOC(SomeStuff)
And then, I implement my components here, where they successfully work
import SomeStuff from "./COMPONENTS/SomeStuff"
function App() {
const list = ['apple', 'orange', 'lemon']
return (
<div>
<SomeStuff data={list}/>
</div>
);
}
export default App;
In the first snippet of a code written above, we created a function that takes "WrappedComponent" as a parameter. This function returns another function, which takes props as a parameter.
MY QUESTION IS:
HOW THE RETURNED FUNCTION KNOWS WHAT PROPS PUT AS PARAMETER, IF WE DID NOT DECLARE THEM ANYWHERE.
We put a component as a parameter to a PARENT function, BUT React SOMEHOW FOUND OUT THAT WE NEED THE PROPS used in this "WrappedComponent"
How this was possible?
Please, please, please help me to find an answer...
Thank you a lot in advance
You did declare them using <WrappedComponent {...props}/>, that will take the props that you passed to the HOC and also pass it down to the child. The spread operator ... will split up the prop array the HOC received and pass it on to the child as individual props, as if you just normally called that component.
SomeStuff is being with data as a prop in main App.
SomeStuff being exported is wrapped by HOC as declared.
export default MyHOC(SomeStuff)
So, component ie. function that is exported from SomeStuff module is somewhat:
(props) => { //these props are the props of a WrappedComponent
return (
<div style={{color: "red", fontSize: "100px"}}>
<WrappedComponent {...props}/>
</div>
)
}
Here, WrappedComponent is SomeStuff and the data (ie. prop) you passed is being passed as it is to the SomeStuff component.
HOW THE RETURNED FUNCTION KNOWS WHAT PROPS PUT AS PARAMETER, IF WE DID
NOT DECLARE THEM ANYWHERE.
When you peform:
<SomeStuff data={list}/>
you're passing the data prop into the SomeStuff (wrapped) component, which is exported here:
export default MyHOC(SomeStuff)
this first calls the MyHOC() function and returns the (props) => { function, which acts as the wrapping component for SomeStuff. This wrapping component is used when we export it (seen above at the beginning of this answer). As a result, the wrapping component gets passed through data={list} which is accessed via the props argument of the returned (props) => { function - in your example, props would be an object that looks (roughly) like so {data: list}.
React SOMEHOW FOUND OUT THAT WE NEED THE PROPS used in this
"WrappedComponent"
Your wrapping component is able to forward the props object into the actual SomeStuff component via the spread syntax:
<WrappedComponent {...props}/>
this takes every (own-enumerable) key: value pair from the props object, and adds it as a key={value} prop to the target component (that being the actual SomeStuff component).

Getting error 'Objects are not valid as a React child' when mapping over imported object that points to components

I have an array in another file that I import and map over in a separate component. One of the properties that is being mapped over, called component, is a reference to another separate component.
I'm trying to get the component to render, but it's throwing the error below and in the title:
Objects are not valid as a React child (found: object with keys {component}). If you meant to render a collection of children, use an array instead.
I've looked around and haven't managed to find quite what I'm looking for. Is what I'm trying to do possible?
I export the array like this:
import Component1 from "./Component1";
import Component2 from "./Component2";
export default [{ component: Component1 }, { component: Component2 }];
And in my component, I try to render these components as,
export default function App() {
return <>{dict.map(({ component }) => component)}</>;
}
I've tried doing something like.
export default [{ component: <Component1 /> }, { component: <Component2 /> }];
But that doesn't even compile.
I guess another option would be to create an object in my App component. Something like,
const componentMap = {
Component1: <Component1 />,
Component2: <Component2 />,
}
and change up my dict object as,
export default [{ component: 'Component1' }, { component: 'Component2' }];
I'm wondering why my current approach is not working. What am I doing wrong here?
You are just returning the functions but to render the JSX you need to do:
export default function App() {
return <>{dict.map(({ component: Component }) => <Component />)}</>;
}
Note: Make first letter capital as component is not a native element which would throw error.

How to set default values on imported components in REACT

Lets say I am using a <FormattedNumber > that I am importing from react-intl
It has a property called minimumSignificantDigits, so that if I set it all my numbers look awesome like 1.00... great when you are working with currencies.. so I can use it like this:
<FormattedNumber minimumSignificantDigits={3} value={somevar}>
I have about 100 of these on the page and I don't want to keep setting this minimumSignificantDigits property on every single on of them, and then when the client changes his/her mind I have to update all of them.
Is there any way that I can set/override some default properties on that component when I import it.
Obviously yes, make a wrapper around <FormattedNumber>
// TreeCharFormattedNumber.jsx
export default TreeCharFormattedNumber = ({ value }) => (
<FormattedNumber minimumSignificantDigits={3} value={value}>>
);
// YourComponent.jsx
import TreeCharFormattedNumber from "./TreeCharFormattedNumber";
...
<div>
<TreeCharFormattedNumber value={myAwsomeValue} />
</div>
...
You can also put TreeCharFormattedNumber in the same file leaving export default
Wrap the imported component with another.
In this example, the default value for minimumSignificantDigits would be 3 with any other props passed through as is. (This allows you to also override your default on a per component basis if required)
function FormattedNumberWithDefault(props) {
return (
<FormattedNumber minimumSignificantDigits={3} {...props}>
)
}
Wrap it with your own component:
export const MyFormattedNumber = (props) => (
<FormattedNumber minimumSignificantDigits={3} {...props}>
);
Now you can import it whenever it's needed, and everything you'll pass to MyFormattedNumber will be passed to the wrapped FormattedNumber:
<MyFormattedNumber value={3} />
You can easily override the default if you pass the property minimumSignificantDigits, because spreading the props can replace the default prop as well:
<MyFormattedNumber minimumSignificantDigits={15} value={somevar}>
I have found that the following also works:
import React from 'react'
import {FormattedNumber} from 'react-intl'
import {Link} from 'react-router-dom'
FormattedNumber.defaultProps = {
style: 'decimal',
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}

If I need to get properties for a component from an API should I do that before the component loads?

Say I have a comp that is inside of a Scene (react-native-router-flux). It lets people choose their favorite fruits.
import React, {Component} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import {MKCheckbox} from 'react-native-material-kit';
var styles = StyleSheet.create({});
export default class PickAFruit extends Component {
render() {
console.log(this.props.fruits);
return (
<View>
{
this.props.fruits.map((x)=> {
return (
<View key={x.key}>
<Text>{x.key}</Text>
<MKCheckbox checked={this.props.checked} key={x.key} onCheckedChange={(e) => {
this.props.update(e, '' + x.key)
}}/>
</View>
)
})
}
</View>
)
}
}
In the parent comp I'm loading the list of fruits from an API in the didMount:
componentDidMount() {
ApiInst.getFruits().then((fruits) => {
console.log(fruits);
console.log(this.props.fruits);
this.props.fruits = fruits;
});
}
I'm also setting a default fruits array in the parent class. It seems like the properties won't load via the API though, the list of fruit is always the "unknown" value, never the new values. Do I need to load the list of fruits before the Profile scene is loaded? When is the correct time to set properties for a component if they will come from an API?
setState seems like the easy answer but these settings don't "feel" like state, they feel like properties that would be injected at build-time (i.e. when the component is built, not the app). Is this a distinction without a real difference?
You can't modify props. Props are passed from parent to child component, and only the parent can change them.
Use setState instead:
this.setState({fruits: fruits});
And access them from state:
<PickAFruit fruits={this.state.fruits} />
You may also want to set a default state in the component constructor:
constructor(props) {
super(this);
this.state = {fruits: null};
}
this.props.fruits = fruits;
won't effect child component, and to be honest - I'm not sure it will work at all. If you don't want to use flux architecture I think the best solution is to update parent's state on componentDidMount() and pass it as props to child component:
componentDidMount() {
ApiInst.getFruits().then((fruits) => {
this.setState({fruits: fruits});
});
}
render() {
return (
<PickAFruit fruits={this.state.fruits} />
);
}
Every state change will invokre render() method, so after API call PickAFruit component will be rerendered, with fruits passed as a props.

Categories