I am trying to access the props in my child component, I am rendering a grid row using a mapped json result:
getRowNodes: function() {
return this.props.contacts.map(function(contact){
return <Row
key={contact.id}
contact={contact}
columns={this.props.children} />;
}.bind(this));
}
When I render the component I can console log {this.props.data} and see all the properties, I can also see all the properties in chrome dev tools, however, when I try and access a property this.props.data.propertyName I get undefined.
If I try and access any of the properties below I get an error..any ideas?
Like Kirill Slatin said: You have to wrap it.
Try this:
getRowNodes() {
return (
<div>
{this.props.contacts.map(this._getRow)}
</div>
);
},
_getRow(contact) {
return (
<Row
key={contact.id}
contact={contact}
columns={this.props.children} />
);
}
NOTE: I have optimized the readability by using JSX Syntax.
Related
I'm very green at react, and I'm trying to learn the library by messing around a bit.
I'm having problems passing an object to another component.
Ive created an array of objects that holds 2 string variables, 1 function and 1 int.
I'm trying to populate this inside a Grid container(Material UI framework).
When I pass the object to the other react component, it arrives as undefined. Ive tried to check if I'm passing a valid object by logging it to the console first, and it is valid.
I've also tried to refer to the properties in the component that receives the object, but the browser console throws Uncaught TypeError: Cannot read properties of undefined (reading 'person').
Does anyone know why it is being sent as undefined?
PersonList.js:
const personListe = [
{
firstName:'testFirstname',
lastName:'testLastName',
getFullName:function()
{
return `${this.firstName} ${this.lastName}`
},
age:28
}
]
export default function PersonList() {
return (
<>
<Grid container spacing={3}>
{personListe.map((person) => {
return(
<Grid item xs={3} key={person.firstName}>
<PersonCard person={person} />
</Grid>
)
})}
</Grid>
</>
);
}
PersonCard.js:
export default function PersonCard({props})
{
return (<>
{console.log(props)}
</>)
}
The PersonCard Component recieves props object which includes the person object inside it.
export default function PersonCard({person})
{
return (
<>
{console.log(person)}
</>
)
}
OR
export default function PersonCard(props)
{
return (
<>
{console.log(props.person)}
</>
)
}
I am building a website that is reliant on a json file for all of its information.
In my app.js the json info is showing properly when I console.log() it, but when I try and pass it to my functional components it is giving me undefined.
in app.js
<Route
exact
path="/puppies"
render={props => (
<Puppies {...props} propdata={this.state.propdata} />
)}
/>
This seems to be working fine, however when I try and map it inside the component it tells me that its undefined.
function Puppies(propdata) {
return <div>{propdata.puppies.map(puppies =>
<h1>{puppies.name}</h1>
)}</div>;
}
I have done this before but with a class component. So most likely I am making a mistake with the functional component.
The full code is viewable here:
https://github.com/Imstupidpleasehelp/Puppywebsite/tree/master/src
Thank you for your time.
You'll probably need to check that the data is null of undefined. You are passing a big object with data, I recommend to pass more specific props instead of a big object.
I like to prevent my data to be undefined in 2 ways:
lodash.get
Optional Chaining
Usage:
import _ from 'lodash';
function Puppies({ propdata }) {
const puppies = _.get(propdata, 'puppies', []);
return (
<div>
{puppies.map(puppies => <h1>{puppies.name}</h1>)}
</div>
);
}
or
function Puppies({ propdata }) {
const puppies = propdata?.puppies || [];
return (
<div>
{puppies.map(puppies => <h1>{puppies.name}</h1>)}
</div>
);
}
What you have as propdata is actually just an object containing all properties that you have passed in. You should use destructuring to get the actual propdata value.
Solution:
function Puppies({propdata}) {
return (
<div>
{propdata.puppies.map(puppies =>
<h1>{puppies.name}</h1>
)}
</div>
);
}
Since this is asynchronous request to get the data, your data is not readily available hence you need to handle that scenario.
function Puppies(propdata) {
return (
{
propdata.puppies.length>0 ? <div>
propdata.puppies.map((puppies)=>{
<h1>{puppies.name}</h1>
})
</div> :null
}
)
Hi I have some sort of the following code:
class First extends Component {
constructor(props){super(props)}
myfunction = () => { this.card //do stuff}
render() {
return(
<Component ref={ref => (this.card = ref)} />
)}
}
Why is it not possible for me to access the card in myfunction. Its telling me that it is undefined. I tried it with setting a this.card = React.createRef(); in the constructor but that didn't work either.
You are almost there, it is very likely that your child Component is not using a forwardRef, hence the error (from the React docs). ref (in a similar manner to key) is not directly accesible by default:
const MyComponent = React.forwardRef((props, ref) => (
<button ref={ref}>
{props.children}
</button>
));
// ☝️ now you can do <MyComponent ref={this.card} />
ref is, in the end, a DOMNode and should be treated as such, it can only reference an HTML node that will be rendered. You will see it as innerRef in some older libraries, which also works without the need for forwardRef in case it confuses you:
const MyComponent = ({ innerRef, children }) => (
<button ref={innerRef}>
{children}
</button>
));
// ☝️ now you can do <MyComponent innerRef={this.card} />
Lastly, if it's a component created by you, you will need to make sure you are passing the ref through forwardRef (or the innerRef) equivalent. If you are using a third-party component, you can test if it uses either ref or innerRef. If it doesn't, wrapping it around a div, although not ideal, may suffice (but it will not always work):
render() {
return (
<div ref={this.card}>
<MyComponent />
</div>
);
}
Now, a bit of explanation on refs and the lifecycle methods, which may help you understand the context better.
Render does not guarantee that refs have been set:
This is kind of a chicken-and-egg problem: you want the component to do something with the ref that points to a node, but React hasn't created the node itself. So what can we do?
There are two options:
1) If you need to pass the ref to render something else, check first if it's valid:
render() {
return (
<>
<MyComponent ref={this.card} />
{ this.card.current && <OtherComponent target={this.card.current} />
</>
);
}
2) If you are looking to do some sort of side-effect, componentDidMount will guarantee that the ref is set:
componentDidMount() {
if (this.card.current) {
console.log(this.card.current.classList);
}
}
Hope this makes it more clear!
Try this <Component ref={this.card} />
I'm using a thing called react-firebase-js to handle firebase auth, but my understanding of react and of the provider-consumer idea is limited.
I started with a built a very big JSX thing all at the top level, and that works without warnings. But when I try to break it into components, I got the warning shown in the title and a few others.
This works without warning...
// in App.js component
render() {
return (
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<FirebaseAuthConsumer>
{({ isSignedIn, user, providerId }) => {
if (isSignedIn) {
return (
// ui for signed in user
);
} else {
if (this.state.confirmationResult) {
return (
// ui to get a phone number sign in
);
} else {
return (
// ui to verify sms code that was sent
);
}
}
}}
</FirebaseAuthConsumer>
</header>
);
}
But this, better design, I thought, generates errors/warnings...
// in App.js component
render() {
return (
<MuiThemeProvider>
<FirebaseAuthProvider {...config} firebase={firebase}>
<div className="App">
<IfFirebaseAuthed>
<p>You're authed buddy</p>
<RaisedButton label="Sign Out" onClick={this.signOutClick} />
</IfFirebaseAuthed>
<IfFirebaseUnAuthed>
<Authenticater /> // <-- this is the new component
</IfFirebaseUnAuthed>
</div>
</FirebaseAuthProvider>
</MuiThemeProvider>
);
}
// in my brand new Authenticator component...
render() {
return (
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<FirebaseAuthConsumer>
{({ isSignedIn, user, providerId }) => {
if (isSignedIn) {
return (
<div>
<pre style={{ height: 300, overflow: "auto" }}>
{JSON.stringify({ isSignedIn, user, providerId }, null, 2)}
</pre>
</div>
);
} else {
if (this.state.confirmationResult) {
return (
// ui to get a phone number sign in
);
} else {
return (
// ui to verify an sms code that was sent
);
}
}
}}
</FirebaseAuthConsumer>
</header>
);
}
The errors/warnings look like this...
[Error] Warning: React does not recognize the isSignedIn prop on a
DOM element. If you intentionally want it to appear in the DOM as a
custom attribute, spell it as lowercase issignedin instead. If you
accidentally passed it from a parent component, remove it from the DOM
element.
[Error] Warning: React does not recognize the providerId prop on a
DOM element. If you intentionally want it to appear in the DOM as a
custom attribute, spell it as lowercase providerid instead. If you
accidentally passed it from a parent component, remove it from the DOM
element.
[Error] Error: Unable to load external reCAPTCHA dependencies!
(anonymous function) (0.chunk.js:1216) [Error] Error: The error you
provided does not contain a stack trace.
Am I misunderstanding how to use provider-consumers, or is there an error in the react-firebase code, or am I doing some other thing wrong? Thanks.
Presumably, this line must be the culprit:
<FirebaseAuthProvider {...config} firebase={firebase}>
Your config object currently holds fields isSignedIn and providerId, and you must be sending those down to children components, and ultimately to a DOM element. Try removing those fields from the object before you send them down:
const { providerId, isSignedIn, ...authProviderConfig } = config
That way, your object authProviderConfig will not hold the providerId or isSignedIn attributes.
Even better, you can rebuild the configuration object explicitly to avoid any further confusion:
const authProviderConfig = { /* The fields from config FirebaseAuthProvider actually needs */ }
You should also check your FirebaseAuthProvider component to see how it's using those props, and avoid spreading them down to DOM elements.
Related documentation: https://reactjs.org/warnings/unknown-prop.html
This warning appears because you passed a prop on a component that it is not valid.
For example, this
<Component someUnknowprop='random-text' />
will trigger the warning. In order to get rid of the warning you should find out where that warning is coming from. The stack trace should give you a hint.
Adding $ to the prop name fixed it for me.
.tsx file:
<Wrapper $offset={isOffset}>
And on the .style.tsx file:
height: ${({ $offset }) => ($offset ? 'calc(100% + 20px)' : '100%')};
In my case, I was getting this error when using the IfFirebaseAuthed component from react-firebase.
You must make sure that you return a function inside of this component.
I changed this:
<IfFirebaseAuthed>
... My authenticated code here ...
</IfFirebaseAuthed>
To this:
<IfFirebaseAuthed>
{() => (
... My authenticated code here ...
)}
</IfFirebaseAuthed>
And this issue went away.
Check your custom props
In my case, I created a reusable hide component. (Initially, it mounts a button with text masked(******) on clicking this button the key( API key ) will be revealed which is a CopyToClipboard component )
const [hide, setHide] = useState(true);
If hide is true, I am rendering a Button ( spreading all the props )
<Button onClick={() => setHide(false)} {...props}>
******
</Button>
When this button is Clicked hide is false and I am rendering a CopyToClipboard component.
<CopyToClipboard
{...props}
>
{value}
</CopyToClipboard>
The Problem
In the above scenario, I am spreading {...props} to both Button and CopyToClipboard components.
But some props of CopyToClipboard are not compatible with that of Button's.
Fix
So at the top of the component destructure the props that are specific to a component (here CopyToClipboard).
Now safely spread the rest of the props to both the components and pass the new prop separately ( to CopyToClipboard component )
const {onCopy, ...restProps} = props
<Button onClick={() => setHide(false)} {...restProps}>
******
</Button>
<CopyToClipboard
onCopy={onCopy}
{...props}
>
{value}
</CopyToClipboard>
I'm really new to web programming.
Is this function React, JSX, or others?
How do I get console log from this function? For example, printing out children and/or router values to console log.
I'd like to hide 'prev' when current page is a specific page. How can this be done?
Thanks in advance.
const App = ({children, router}) => (
<div className="App">
<Stepper/>
<div className='App-main'>
<Row gutter={40}>
<Col span={20}>
{ children }
</Col>
<Col span={4}>
<Navigator
label={label(router.location.pathname)}
action={action(router, router.location.pathname)}
prev={prev(router.location.pathname)}
/>
</Col>
</Row>
</div>
</div>
)
As Zfrisch mentioned, it's a mix. App is a functional component (React), the stuff returned in the function is XML.
The rounded brackets are an implicit return. If you change it to curly braces, you can do stuff then return ( xmlGoeshere ); Example:
const App = ({children, router}) => {
console.log("hello world");
return (
<div className="App">
etc...
);
};
It's hard to answer this in a way that works for you without more info. You can either use a ternary to make prev falsy, you can change the prev function, or modify the Navigator's render depending on what you want to achieve.