How to use props within the same component? - javascript

I am looking to make a component that is filled with tweets.
I am creating an array called "tweets" and I would like to access the array in the return(). I know about mapping, but is there a way to just display one on the page? I thought it would be like {this.props.name} or just {props.name} but it doesn't render anything to the page.
How can I reference the props to my page within the same component?
Tweets.js
import React from 'react';
const Tweets = (props) => {
const tweets = [
{name: 'Name 1',
tweet:'This is a tweet!'},
{name:'Name 2',
tweet:'This is another tweet'},
{name:'Name 3',
tweet:'This is yet another tweet!'},
]
return (
<section>
<h1>{this.props.name}</h1>
</section>
)
}
export default Tweets;

Your tweets are inside the component itself, they are not coming from props. So you can access a single value with something like this:
{tweets[0].name}
If you want to display them all, you can do something like this:
return (
<section>
{
tweets.map(({name, tweet}) => (
<div>
<h1>{name}</h1>
<p>{tweet}</p>
</div>
))
}
</section>
)

Related

How to fix unique "key" prop and validateDOMNesting(...) in ReactJS with fuctional component

Hi all I have following code.
Test.js component
const Test = ({ infoText }) => {
return (
<div>
Some Text
{infoText && <p>{infoText}</p>}
</div>
);
};
export default Test;
App.js component
export default function App() {
return (
<div className="App">
<Test
infoText={[
<p className="someStyles">"Looking to lease multiple devices?"</p>,
<div className="someOtherStyles">
<b>Get in contact with our specialist.</b>
</div>,
]}
/>
</div>
);
}
When I am rendering my Test component in App.js file I am getting errors like
Warning: Each child in a list should have a unique "key" prop.
Warning: validateDOMNesting(...): <div> cannot appear as a descendant of <p>.
I know that is coming from this syntax that I wrote.
infoText={[
<p className="someStyles">"Looking to lease multiple devices?"</>,
<div className="someOtherStyles">
<b>Get in contact with our specialist.</b>
</div>,
]}
I need to write in this way because my Test component is reusable component and I am using it's infoText prop for passing various tags with specific classes.
By the way, the code works. But it's very ugly that I have so many errors in the console. Please help me fix this.
This warning is generated because usually, when a react element is an array, that array is generated dynamically, and so might change. In this scenario, you absolutely need the elements in your list to have a unique key prop to avoid unexpected behaviour from React.
In this scenario, you are absolutely fine to ignore the warnings, because your array is hardcoded, and is never going to change. If you don't want to see these warnings, you could change the array to be a react fragment, like this:
const Test = ({ infoText }) => {
return (
<div>
Some Text
{infoText && <p>{infoText}</p>}
</div>
);
};
<Test
infoText={
<>
<p className="someStyles">"Looking to lease multiple devices?"</p>
<div className="someOtherStyles">
<b>Get in contact with our specialist.</b>
</div>
</>
}
/>
A more idiomatic way of achieving the same thing might be to have your Test component render its children, like this:
const Test = ({ children }) => {
return (
<div>
Some Text
<p>{children}</p>
</div>
);
};
<Test>
<p className="someStyles">"Looking to lease multiple devices?"</p>
<div className="someOtherStyles">
<b>Get in contact with our specialist.</b>
</div>
</Test>

Trouble iterating/mapping props

I'm trying to develop a simple application in which any number of tasks will be rendered as cards. I'm passing them as props, schemed like so:
taskList: [{
taskID: 1,
taskTitle: 'Task 1',
taskDescription: 'Description 1',
completed: true
}]
By logging the props in the TaskCard component, I can see the list arrives exactly like that. If I try and log something such as props[0].taskDescription, it'll successfully return "Description 1", like so:
export default function TaskCard(props) {
return(
<div className="task-card" draggable>
<h3> Test </h3>
{ props[0].taskDescription } // this actually works
</div>
)
}
I can't, however, map or calculate the length of the props to iterate through props.
What am I doing wrong in terms of iteration? Is it a flawed architecture in terms of componentization?
To render a list of TaskCards, you need to do the mapping of taskList outside that component like so:
{taskList.map(task => <TaskCard task={task} />)}
and then TaskCard would render using the passed task props:
TaskCard(props) {
// use props.task.taskDescription, etc.
}
First, thank you all who contributed with your insights in the comments for the original posting. So yes, apparently passing an array as a prop is troublesome. I may not have resolved in the most efficient way, but here's what it has come down to so far. Use the image in the original post to guide yourself.
I have resolved the issue the following way:
UserArea.jsx
Contains a state that logs the user, username, a list containing pending tasks pendingList and a list containing complete tasks completedList;
It renders a header, the PendingArea and CompleteArea component passing {...this.state} to each of them (the full component is an object).
render(){
return(
<div className="user-area-container">
<div className="profile-header">
<h2>{ this.state.userName }</h2>
{ this.state.email }
</div>
<PendingArea {...this.state} />
<CompletedArea {...this.state} />
</div>
)
}
PendingArea.jsx and CompleteArea.jsx
Here I made the filtering, passing only the equivalent mapping to each of the components. The code for the PendingArea component is as follows:
function PendingArea(props) {
var pendingTasks = props.pendingList.map(task => {
return <TaskCard {...task} />
});
return(
<div className="status-container">
<div className="status-title">
<h2>Pending tasks</h2>
</div>
<div className="status-modifier">
{ pendingTasks }
</div>
</div>
)
}
TaskCards.jsx
Finally, the TaskCard component uses the direct properties from the props:
export default function TaskCard(props) {
return(
<div className="task-card" draggable>
<h3> { props.taskTitle } </h3>
{ props.taskDescription }
</div>
)
}
This way I managed to properly render the task card in their due place. I hope this works for anyone reading this, as well.

How to append a dynamic HTML element to React component using JSX?

I'm new to Reactjs. I'm creating an App with a Survey creation like Google Forms. My component has a button to create a new Div with some HTML elements to create a survey question. To do that, on the button click function, I'm creating a JSX element and push it to an array. And then, I set the array inside the render function to display what inside it.
The problem is, Even though the Array is updating, the dynamic HTML part can not be seen on the page. The page is just empty except the button. How can I fix this?
Component:
import '../../styles/css/surveycreation.css';
import React, { Component } from 'react';
let questionId = 0;
class SurveyCreation extends Component {
constructor(props) {
super(props);
this.questionsList = [];
this.state = {
}
}
addQuestion = (e) => {
e.preventDefault();
questionId = questionId + 1;
this.questionsList.push(
<div key={questionId}>
question block
</div>
)
}
render() {
return (
<div>
<button onClick={e => this.addQuestion(e)}>Add Question</button>
<div>
{this.questionsList}
</div>
</div>
);
}
};
export default SurveyCreation;
The only way a react component knows to rerender is by setting state. So you should have an array in your state for the questions, and then render based on that array. In the array you want to keep data, not JSX elements. The elements get created when rendering.
constructor(props) {
super(props);
this.state = {
questions: [],
}
}
addQuestion = () => {
setState(prev => ({
// add some object that has the info needed for rendernig a question.
// Don't add jsx to the array
questions: [...prev.questions, { questionId: prev.questions.length }];
})
}
render() {
return (
<div>
<button onClick={e => this.addQuestion(e)}>Add Question</button>
<div>
{this.state.questions.map(question => (
<div key={question.questionId}>
</div>
)}
</div>
</div>
);
}
I think you're component is not re-rendering after you fill the array of elements.
Try adding the questionsList to the component's state and modify your addQuestion method so that it creates a new array, finally call setState with the new array.
You need to map your this.questionsList variable.
You can save the 'question string' in the array and then iterate the array printing your div..
Something like this.
<div>
{this.state.questionsList.map(questionString, i => (
<div key={i}>
{questionString}
</div>
)}
</div>

Passing down props returning undefined

main component
const items = [{name: 'a'}, {name: 'b'}, {name: 'c'}]
render={() => (
<LinksComponent
items={items}
/>)}
Links Component
const LinksComponent = ({ items }) => (
<div>
{items.map((item) => {
return <div>{item.name}</div>
})}
</div>
)
I must be missing something really simple but I have my main component and this react-router renders my link component. it is all wired up correctly because when I had hello world rendering it showed. now I'm trying to pass items down can't seem to display them. it keeps saying it can't read map of undefined. any ideas?
Okay I worked on it. I passed props down at max 2 level. And also added Router wrapping before div.
See the solution here - https://codesandbox.io/s/ly63qwjm49

react higher order component

Im looking into higher order functions and i dont really understand how this part works.
say i have the following function:
const withAdminWarning = WrappedComponent => {
return props => (
<div>
{props.isAdmin && <p>This is private info. Please dont share!</p>}
<WrappedComponent {...props} />
</div>
);
};
const Info = props => (
<div>
<h1>Info</h1>
<p>This info is: {props.info}</p>
</div>
);
const AdminInfo = withAdminWarning(Info);
ReactDOM.render(
<AdminInfo isAdmin={true} info="There are the details" />,
document.getElementById("app")
);
From my understanding of components, to access the props variable, you have to use either props, if its a stateless component, or this.props if it is a class component.
From where does the props come into play in the example above as i cant get access to it from the WrappedComponent or anywhere else apart from the return statement.
The Higher order Component returns a function which is a functional component. Am I right in thinking that foo(Info) means withAdminWarning(Info)?
So after calling withAdminInfo the AdminInfo Component looks basically like:
const AdminInfo = props => (
<div>
{props.isAdmin && <p>This is private info. Please dont share!</p>}
<div>
<h1>Info</h1>
<p>This info is: {props.info}</p>
</div>
</div>
);

Categories

Resources