Why key is null?, despite I created it - javascript

I created a list based in an array using a custom component, and it works, but not properly, because I did try to send a 'key' prop in the component implementation, but inside the component, key prop doesn't exist, is just undefined.
The expected behaviour is to access to the 'key' prop inside the component, and avoid the "key is not a prop" warning on my app.
This is the data
data: [
{ key: 1, definition: "Def 1", example: "Example text 1" },
{ key: 2, definition: "Def 2", example: "Example text 2" },
{ key: 3, definition: "Def 3", example: "Example text 3" }
]
This is the component implementation
createDefinitions = (data) => {
return data.map((item, index) => {
return <Definition {...item}/>
})
}
'item' is an object with every duple in the previous array. Actually, I tried to add 'key' prop directly in this point, but it was the same.
Inside the custom component I tried to print the props object, but 'key' doesn't exist
<Text>{JSON.stringify(props)}</Text>
You can the code here https://snack.expo.io/r1VE3DiQV
The expected behaviour is to get key property inside custom component.
Thanks!

tl;dr you cannot access a key via this.props.key. If you need the value that you set for the key pass it via a different name such as id.
You cannot access the key property via props once you have set it. If you try to access it you will get the following yellow warning
Warning: %s: key is not a prop. Trying to access it will result in
undefined being returned. If you need to access the same value
within the child component, you should pass it as a different prop.
https://reactjs.org/warnings/special-props.html
I've used the actual url that the link resolves to as SO complains about the use of shortened urls
Following the link in the warning gives you the following message:
Most props on a JSX element are passed on to the component, however,
there are two special props (ref and key) which are used by React, and
are thus not forwarded to the component.
It then goes on to tell you that if you require access to the value you should set it as a different prop.
For instance, attempting to access this.props.key from a component
(i.e., the render function or propTypes) is not defined. If you need
to access the same value within the child component, you should pass
it as a different prop (ex:
<ListItemWrapper key={result.id} id={result.id} />). While this may seem redundant, it’s important to
separate app logic from reconciling hints.
Looking at your code it, is working fine, the only issue is that you are trying to access the key which isn't passed via props. If you remove the references to props.key in your Definition component the warning should go.

You are creating a list of elements by mapping over your data, and in that case you need to add a key prop (with a string value) to each list element. This is completely unrelated to the data object you are using, but you could use that key as prop value. So in this case you need to add a key prop to Definition:
createDefinitions = (data) => {
return data.map((item, index) => {
return <Definition key={item.key.toString()} {...item}/>
})
}
Alternatively, you could also use the index if you don't have unique keys in your data

Related

Vue2 - Accessing to methods of a component with a generated ref name

I'm trying to access to a method of an child component, to validate multiple forms.
I have an array named "forms", each form object has a randomly generated id. Based on these form objects I generate components and give them a ref name
In my validateAll method I'm trying to loop over all forms, find components with their id as component's ref name. When I find the component (no problem so far), I try to call the child's method. But I get an error.
This is where I render components with v-for loop:
<SupportRequestForm v-for="(form, idx) in forms" :key="form.id"
...
:ref="`formRef${form.id}`"
/>
This is validateAll method, where I try to access child method:
validateAllForms() {
return this.forms.find(form => {
const formComponent = this.$refs[`formRef${form.id}`]
console.log(formComponent)
return formComponent.validateForm()
})
}
And this is the error:
I can access child component's method when it's a static ref name but I can't do the same thing when the is generated on the spot. Is this an expected behaviour or am I doing something wrong ?
Thank you very much in advance.
No need to bind each form to the form id, just create one ref called forms and since it's used with v-for it will contain the forms array :
When ref is used together with v-for, the ref you get will be an array containing the child components mirroring the data source
<SupportRequestForm v-for="(form, idx) in forms" :key="form.id" ref="forms" />
in method :
validateAllForms() {
this.$refs.forms.forEach(formComponent=> {
formComponent.validateForm()
})
}

How to print Clarifai API returned response?

help... I'm making a project that detects food ingredients using Clarifai API Food model. When the API scans the image, it returns the response via console.log. How do you get THAT output from the API (console.log) and print it in the webpage. sorry, newbie aspiring web dev here.Image of website,console.log, and JS code
Instead of console logging the response, you should define a key value pair in the state of the component:
// the initial value of each key in state should match what data you are storing
this.state = {
input: '',
foodUrl: '',
prediction: {},
};
After the file has received the API response, instead of console logging the response you would write:
this.setState({ prediction: response.outputs[0].data.concepts[0] });
Next you would pass it in to the component you are using to display the response within the render portion of App.js:
<ComponentToRenderAPIResponse prediction={this.state.prediction} />
Within that child component, you would then write something like this within the render portion:
render() {
return (
<div>`Detected Food: ${prediction.name}`</div>
<div>`Prediction Value: ${prediction.value}`</div>
)
}
Instead of storing the entire object displayed in your console, you could just access the name and value key value pairs and store them as separate fields within your state object. Then pass both the name and value as different props to the child component. Also you might want to consider different html tags than the divs I used above as well as adding CSS styling to both tags.

How to get value from array of objects?

I have an react app, and using redux and props to get array of objects into my component, and i am getting them. But i can't access particular property inside of one of objects that are in that array.
With this:
console.log(this.props.users)
I get listed array with all objects inside it. But when i need to access particular object or property of that object, for example:
console.log(this.props.users[0])
console.log(this.props.users[0].name)
I am getting error:
Cannot read property '0' of undefined
But when I iterate through array with map() method i have access to it, it works. Why can't i access it normally?
You are trying to access properties of this.props.users before it has loaded. Your component renders without waiting for your data to fetch. When you console.log(this.props.users) you say that you get an array, but above that, it probably logs undefined at least once when the component renders before this.props.users has loaded.
You have a couple of options. You can either do this at the very top of your render method to prevent the rest of the code in the method from executing:
if (!this.props.users) return null;
Once the data is fetched and props change, the render method will be called again.
The other option is to declare a default value, of an empty array for users in your reducer.
Might be when you are executing that line this.props.users is undefined. Check the flow where you have added console.log(this.props.users[0])
const App = () => {
const example = () => {
const data =[{id:1 ,name: "Users1", description: "desc1"},
{id:2 ,name: "Users2", description: "desc2"}];
return (
<div>
{data.map(function(cValue, idx){
console.log("currentValue.id:",cValue.id);
console.log("currentValue.name:",cValue.name);
console.log("currentValue.description:",cValue.description);
return (<li key={idx}>name = {cValue.name} description = {cValue.description}</li>)
})}
</div>
);
}
return(
<p style = {{color:'white'}}>
{example()}
</p>
);
}
export default App;

Multi level props in react

I've recently started learning react. I can't understand this:
this.props.message.text
I know that message is an object with a key value pair in it, the key being text.
But my problem is when we want to pass the prop to the component:
<Component message={message}>
My question is why should we write message={message}?
Why shouldn't we write message={message.text} instead so that we know we want text?
How does it know we want text in the message object?
It depends on what the Component is doing. Let's say you have more properties in your message object, e.g :
{
text: 'this is my message',
author: 'odiwxe',
sentAt: '2018-05-30T12:30:00'
}
Then your Component might want all that information in order to display it so you could pass it as you have done like:
<Component message={message}>
Otherwise, if your Component only cares about the message text you could potentially change it to something like this:
<Component messageText={message.text}>
It's up to you!
Actually, it does not.
When we want the text of the message we have to access the data using the props passed to the child component in this way:
{this.props.message.text}
So, when any child component requires data which is sent by it's parent you need to tell the object name in which you require the data in child.
for Example:
<Parent Component {
//Some code//
<ChildComponent propsName = {propsData}
}
Then this data will be accessible in child component in this form:
<ChildComponent
{this.props.propsName}
}
So, this is the way of passing the data from parent to child and for achieving this you need to use props.
//Update
It has used task for the task but task.id for the key because they just want the key in that case and task object is used in the component for some other functioning like printing the text written in that which cannot be fetched from task.id individually.
According to me, the task object is somewhat like this:
task{
"text": "value"
}

Reactjs: Key undefined when accessed as a prop

Tools: Reactjs 0.14.0 Vanilla Flux
I need unique identifiers for 2 reasons:
Child Reconciliation
Keeping track of what child was clicked
So let's say I have a list of messages that looks like this:
[
{
id: 1241241234, // <-----The unique id is kept here
authorName: "Nick"
text: "Hi!"
},
...
]
And now I use a Array.prototype.map() to create "ownee" component (MessageListItem) inside of the owner component MessageSection
function getMessageListItem(message) {
return (
<MessageListItem key={message.id} message={message} />
);
}
var MessageSection = React.createClass({
render: function() {
var messageListItems = this.state.messages.map(getMessageListItem);
<div>
{messageListItems }
</div>
}
});
But the this.props.key is undefined in the MessageListItem even though I know for a fact that is was defined when it was passed down.
var ConvoListItem = React.createClass({
render: function() {
console.log(this.props.key); // Undefined
}
});
I'm guessing there is a reason that React is not letting key be used as a prop.
Question:
If I can't use key as a prop, then what is the proper way to handle the duality need of keying and setting unique identifiers on a dynamic list of child elements that contain state?
key and ref aren't really 'props'. They're used internally by react and not passed to components as props. Consider passing it as a prop such as 'id'.
It is best to use id. Then in the eventHandler you can have event.target.id.
function getMessageListItem(message) {
return (
<MessageListItem key={message.id} id={message.id} message={message}/>
);
}
As we already established in other answers that you can't use key since it isn't passed as a prop and instead used internally by react. Here is my 2 cents as an alternative:
Since you're passing the entire array of messages as a prop while creating the <MessageListItem> component, you don't necessarily need to pass another prop with id. You can simply use {this.props.message.id} whenever you need to use id.
As you've discovered, the key property is consumed by React itself, not passed to the child component. It's what React uses to keep track of entries in arrays to avoid unnecessarily re-rendering them (both in terms of calling their render and reconciling with the DOM).
Unfortunately, that means if you also want to use it in the child, you have to pass it twice. In your code, you already are passing it twice (once as key, one as part of message). So you can keep your current JSX, just use id from message in the child:
var MessageListItem = React.createClass({
render: function() {
console.log(this.props.message.id);
// ^^^^^^^^^^^−−−−− Has the value
}
});
More:
Lists and Keys
Why keys are necessary (linked from the above)
Special props warning - which tells us that key and ref are special props not passed on to the child component

Categories

Resources