Looping a ReactJS component inside of its parent component - javascript

I have this component imported that returns a bunch of cards but I want to style this in a row instead of a column and it seems the way to do that is to loop the component as a <li> and then adding css but I cannot seem to make the component loop correctly.
the component looks like this inside of the parent element:
<div id="newsFeed" className='feed'>
<Feed theme={this.state.theme} articles = {this.state.articles} />
</div>
I have tried solutions such as:
var feedContent = <Feed theme={this.state.theme} articles = {this.state.articles} />
///////////////////////
{feedContent.map(item => <Feed key={item} value={item} />)}
</div>
but cannot seem to find any luck.
Any help would be greatly appreciated

map is a built in array method that is used a bunch in React. You need to use it on an array or else you will throw an error. I am assuming the value for articles is an array here:
//Feed component
class Feed extends React.Component {
constructor(props) {
super(props);
this.state = {
articles = []
};
}
componentDidMount = () => { // maybe call an API to populate the articles array }
render = () => {
return (
<ul className="someClass" >
{this.state.articles.map((item, index) => <li key={index} className="someOtherClass">{item}</li>)}
</ul>
);
}
}
alternatively you could create a li component, perhaps called FeedItem, import it and map it with the value prop from each item in the articles array.
// render method for Feed Component
render = () => {
return(
<ul className="someClass">
{this.state.articles.map((item, index) => <FeedItem key={index} value={item} />)}
</ul>
);
}
// FeedItem component
const FeedItem = ({value}) => {
return(
<li className="someOtherClass">{value}</li>
);
}
so, you are using map to create a list with the items in your articles array, and the map function loops through each article and returns a list component. Hopefully this helps! here's the React docs for reference: https://reactjs.org/docs/lists-and-keys.html
note: React docs advise against using an index as a key, but I don't know if your article array elements contain something unique. If they do (like an id of some kind), use that instead of index.

I think you need to change the approach.
I'd recommend you create an Article component, example:
function Article({ title }) {
<div>
{title}
<div>
}
After that, you might use the articles array to show each one:
//Feed component
this.state.articles.map((article, i) => <Article title={article.title}>)
In that way you can stylize the articles component as you want.

I was able to figure it out with simple CSS believe it or not. Basically <Feed /> was wrapped in a div in the parent component and was not responding to Flexbox CSS code, however, After I used changed the className of the div that was wrapping the component inside of its <div> within its own file the div responded to CSS! Thank you so much for your help everyone, I appreciate it!

Have you tried adding a className to the div that is the parent of the cards? Use that class to apply a flex display for example, and see what that gives you. If Newscard has a fixed width of 100% by chance, of course you'll need to adjust that to a small percentage / width to suit your needs.

Related

How to nest the class of parent component in child component?

I'm in a learning phase of react and I've been trying to nest style of parent in component in child component via class in react.js. How to do it?
What I've tried until now:
function Card(props) {
const classes = 'card' + props.className;
return (
<div className={classes}>
{props.children}
</div>
)
}
export default Card
I applied style on class 'card' in a CSS file.
Parent component JS code:
import Card from './UI/Card';
function ExpenseItem(props){
return (
<Card className="expense-item">
<ExpenseDate date={props.date} />
<div className="expense-item__description">
<h2>{props.title}</h2>
<div className="expense-item__price">{`₹ ${props.amount}`}</div>
</div>
</Card>
)
}
Now, there are various classes in parent component that are styled accordingly. And I'd like to nest those classes in child component for those style to work.
You can see in the code the way I tried to nest the classes, but it isn't working.
const classes = 'card' + props.className;
What am I doing wrong? And how should I correct it?
You missed a space after the card class name, otherwise i don't see any other issues in your code. Try below, hope it works
const classes = 'card ' + props.className;
Just one note, this will make your components dependent on each other. One of best things about React is that it allows you to have separation of concerns. So Card component is doing Card component staff, displaying some information and needs not be dependent on a parent in this case ExpenseItem.
One way to do it is to use styled-components.

React - How to apply multiple values inside style

I have a certain component named ThemeDoc inside this component there is a context, localStorage, hooks, maps and whatnot, but in the end I get the value of the hooks inside a component named SideBar. I decided that there is no need to demonstrate the contents of the ThemeDoc component in order not to complicate my code and question, but I will attach a link of my project on the github if you want you can see GitHub Project. So as I just mentioned, I get the value of the hooks from the ThemeDoc component for the SideBar component, they look like this
const {SideBarValue, SideBarWallpaperValue, SideBarColor} = React.useContext(CounterContext);
const [SideBarTheme, SetSideBarTheme] = SideBarValue;
const [SideBarBackground] = SideBarWallpaperValue;
const [SideBarColorTheme, SetSideBarColor] = SideBarColor;
These values are used to change the color of the SideBar.
<div style={{background: SideBarTheme}}>
...
</div>
It all looks like this
Please see there are two values for SideBarTheme and SideBarColorTheme, SideBarTheme changes the background of the site to a gradient and the SideBarColorTheme only changes the SideBar color. As you can see I successfully applied the SideBarTheme value inside jsx and everything works fine for me
<div style={{background: SideBarTheme}}>
...
</div>
But I can’t use SideBarColorTheme, I don’t know how to do it, here is my full-fledged code if you need to tell me I will provide the ThemeDoc component
SideBar.jsx
function SideBar(props) {
const {someValue} = useContext(SideBarContext);
const {SideBarValue, SideBarColor} = React.useContext(CounterContext);
const [SideBarTheme, SetSideBarTheme] = SideBarValue;
const [SideBarColorTheme, SetSideBarColor] = SideBarColor;
return (
<div style={{background: SideBarTheme, backdropFilter: `blur(${someValue}px)`}}>
...
</div>
);
}

Manipulating state through an out-of-class function (or alternatives)

hope you're having a good day. I may be about to annoy you slightly with this question given how much of a newbie I am with React.
Here's the setup: I have a "projects" page for my portfolio website where I feature one project in full with the full size image and details on the side, and under that I have a listing of all other projects. As soon as one of those is clicked, the featured project should change. A pretty simple thing to most, I'm sure, but I seem to be stuck.
Here's how I currently have it set up:
An array called 'projects' outside of the component class to store them, one project looks like this:
{
key: 0,
title: "Project title",
description:
"Lorem ipsum",
details: [
"...",
"...",
"..."
].map((detail, i) => <li key={i}>{detail}</li>),
image: ImageObject
},
This function (which is referenced within the class' render method) also outside of the main component class which makes a div for each project
function ProjectList(props) {
const projects = props.projects;
const projectItems = projects.map(project => (
<div key={project.key}>
<a href="#">
<img src={project.image} alt={project.title} />
</a>
</div>
));
return <div className="row">{projectItems}</div>;
}
and the reference in the render method goes like this:
<ProjectList projects={projects} />
Now we're going within the Projects class, with one state value called 'currentProjectIndex', and a 'setProject' function:
setProject = index => {
this.setState({ currentProjectIndex: index });
};
Everything works and displays correctly, and if I manually edit the state it does show the relevant project, but I'm not sure how to proceed here. I've tried adding an onClick attribute to the div and the a tags, but it seems I can't reference setState outside of the main class, which I suppose makes sense, but the ProjectList function isn't recognized in the render method if I place it inside the main class.
I realize this may be some very basic stuff but I have a feeling I might have gone about this process entirely wrongly and that I'm on the completely wrong track here. Either that or I'm just being stupid, both of which are entirely possible. Either way, I'm super thankful for any suggestions!
You can try this: add a button where the click event calls setProject and pass the index (that is the project.key, right?) as parameter. You also may want to add an event.preventDefault. Hope it helps. Here is the code:
setProject = (event, index) => {
event.preventDefault();
this.setState({ currentProjectIndex: index });
};
function ProjectList(props) {
const projects = props.projects;
const projectItems = projects.map(project => (
<div key={project.key}>
<a href="#">
<img src={project.image} alt={project.title} />
</a>
<button
type='button'
onClick={event => { this.setProject(event, project.key) }}
>
Select this project
</button>
</div>
));
return <div className="row">{projectItems}</div>;
}

Reuse React component from render props

I wrote a react component in render props way,it will call children function with 3 react component object ( not sure the name exactly, the variable generated by executing jsx (<div>...</div>) );
<PaginatedTable> Usage example:
<PaginationTable data={data} ...otherprops>
{({ SearchBar, Table, PaginationBar })=>
(<div>
{SearchBar}
{Table}
{PaginationBar}
</div>)
}
</PaginationTable>
with render props, I'm so glad that I can custom these 3 child component object very easily such as rearrange order or adding custom elements between these three.
{({ SearchBar, Table, PaginationBar })=>
(<div>
{PaginationBar}
<h1> my custom search bar text </h1>
{SearchBar}
{Table}
</div>)
}
But now I wish more than arrange order inside , I wish I can move {SearchBar} out of to the same layer of 's sibling 's children such as this picture.
working demo: https://codesandbox.io/s/23q6vlywy
I thought this may be anti-pattern to the unidirectional data flow of React.
Extract {SearchBar} to another independent component then use it as <SearchBar ... /> inside of <ToolBarArea /> is what I learnd from React Doc.
But in this way, I have to do "lifting state up" and write similar function and states already had in <PaginationTable /> like below **text** parts are functions and states already had in <PaginationTable />
class ToolBarArea extends Component{
render(){
return(
<div>
// text
<SearchBar onChange={**this.props.onSearchBarChange**} />
//.... other text or elements
</div>);
}
}
class ContainerArea extends Component {
state={
**searchBarText:'',**
tableData : [{...}, {...}]
}
**onSearchBarTextChange = (event)=>{
this.setState({ searchBarText: event.target.value });
}
filterdTableData = ()=> this.state.tableData.filter(d=>d.name.includes(this.state.searchBarText);
**
}
I really hope there is a way I can simply move the variable {SearchBar} in the render props function out to without knowing is in the parent or parent's sibling or anywhere in the DOM tree.
such as
<ToolBarArea>
{SearchBar} // SearchBar from <PaginationTable />
</ToolBarArea>
Is there a way to reuseonSearchBarTextChange and filtedTableData functions and these **text** codes I already wrote in <PaginationTable /> ?
I believe you hit the nail on the head when you referred to lifting state. If you already wrote a similar function then your best option may be to 'abstract' that function so that it applies to both use cases. You could use a simple flag to differentiate the unique execution each needs. Then finally pass the function down to both components.
If you're adamant about avoiding this approach you could technically get around it by using event listeners to handle data transfer or watch variables in the window but this is for sure an anti-pattern.

Issue with key assignment to dynamic children in React-Rails app

I'm creating a React app on Rails and have encountered a problem regarding key assignment to dynamic children.
Below is a pared-down copy of my code:
class Records extends React.Component {
render () {
var records =
this.props.data.map(function(record) {
return <div>
<Record key={record.id} data={record} />
</div>;
});
return (
<div>
{records}
</div>
);
}
}
class Record extends React.Component {
render () {
return (
<div>
<h1>Title: {this.props.data.title}</h1>
</div>
);
}
}
The code runs correctly except for the warning below that appears on the console:
Warning: Each child in an array or iterator should have a unique "key" prop.
Check the render method of `Records`.
I've followed the link contained within the warning to the React guide (http://facebook.github.io/react/docs/multiple-components.html#dynamic-children).
Though I feel I've implemented their recommendation that the key should always be supplied directly to the components in the array, not to the container HTML child of each component in the array, I still receive this warning in the console.
Does anyone have any ideas why? I completely appreciate any help you might provide!
The problem is that you should add the key props to the outer div, not to your Record instance.
var records =
this.props.data.map(function(record) {
return <div key={record.id}>
<Record data={record} />
</div>;
});
In fact, you don't need the wrapping div at all.
The warning is there because you need to add the key prop to the repeated element, and in your code you have a list of divs, each containing a Record (not a list of Records).
React asks you to do so to be able to "track" (identify) these divs which would be exactly the same without a way to identify them. React needs this ids to efficiently track DOM mutations (e.g. reordering them, removing them, etc)
Then, if you use ES6 (transpiled with Babel or similar) along with JSX you can just to this:
var records = this.props.data.map(record => <Record data={record} key={record.id} />)
In your code sample, the child in the is the surrounding <div> element, not the Record component which has the key property.
Your resulting HTML structure looks like this
<div>
<div><h1 key="1">...</h1></div>
<div><h1 key="2">...</h1></div>
<div><h1 key="3">...</h1></div>
</div>
So indeed React is correct, the collection does not have a unique key for the top-level element.
Your two options are:
(A) Add the key property to the surrounding <div> such that it looks like this
<div>
<div key="1"><h1>...</h1></div>
<div key="2"><h1>...</h1></div>
<div key="3"><h1>...</h1></div>
</div>
var records =
this.props.data.map(function(record) {
return <div key={record.id}>
<Record data={record} />
</div>;
Or
(B) Get rid of the surrounding <div> altogether as it's not needed.
var records =
this.props.data.map(function(record) {
return <Record key={record.id} data={record} />;
Side-note: React expects your render call to only return a single top-level element, so you only need a container element if you want to have multiple sibling elements in a render call.

Categories

Resources