Cleaner react code when using loops and map - javascript

I have this code working with react, and its just getting very cluttered, so I was wondering if there is a way to make this code and others that are quite similar to look cleaner.
render() {
let result = null;
var obj = this.state.welcome;
let test = null;
if (this.state.isReal) {
test = Object.entries(obj).map(([key, value], index) => {
return (
<li key={index}>
Word: "{key}" repeats: {value} times
</li>
);
});
result = (
<Aux>
<h3>Title</h3>
<ul>{test}</ul>
</Aux>
);
}
return (
<Aux>
<div className="bframe">
<div className="form" />
{result}
</div>
<Footer />
</Aux>
);
}
I was wondering if its possible to move everything before 'return' statement, preferable in a separate file. I tried making a functional component and passing props but im unable to do loops there. Any tips?

You can reduce your code to the following :
render() {
const { welcome, isReal } = this.state
return (
<Aux>
<div className="bframe">
<div className="form" />
{isReal &&
<Aux>
<h3>Title</h3>
<ul>
{Object.entries(welcome).map(([key, value]) =>
<li key={key}>
Word: "{key}" repeats: {value} times
</li>
)}
</ul>
</Aux>
}
</div>
<Footer />
</Aux>
);
}
Do not use var, by default use const and if you want to modify your variable, use let.
You can choose to render an element or not by using the inline if : &&.
Your function is also unnecessary as it can be replaced by inline JS.
Your map can also be reduce from : x.map(a => { return <div/> } to x.map(a => <div/>.
You can also use the key of each item as the React key since they all have to be unique anyway in your object.

Maybe something like the following
const Result = ({real, welcome}) => {
if (!real) return null;
const words = Object.entries(welcome).map(([key, value], index) => <li key={index}>
Word: "{key}" repeats: {value} times
</li>
);
return (
<Aux>
<h3>Title</h3>
<ul>{words}</ul>
</Aux>
);
}
class YourComponent extends React.Component {
// ...
render() {
const {isReal, welcome} = this.state;
return (
<Aux>
<div className="bframe">
<div className="form" />
<Result real={isReal} welcome={welcome}/>
</div>
<Footer />
</Aux>
);
}
}

Related

React - component is not rendered

After receiving data from the DB server, you try to render it, but the console log shows the data, but the component is not rendered. What's the reason?
useEffect(() => {
readRequest().then(setTodos);
console.log()
}, []);
return (
<div className="App">
{todos.map((todo) => {
console.log(todo);
console.log(todo.text);
<div key={todo._id}>
{todo.text}
{`${todo.completed}`}
</div>
})}
<p>dfdf</p>
</div>
);
The picture is a screen capture.
Your .map callback does not return anything.
Change the { to (:
return (
<div className="App">
{todos.map((todo) => ( // <-- here
<div key={todo._id}>
{todo.text}
{`${todo.completed}`}
</div>
))}
<p>dfdf</p>
</div>
);
Or use the return keyword.
return (
<div className="App">
{todos.map((todo) => {
return (<div key={todo._id}>
{todo.text}
{`${todo.completed}`}
</div>);
})}
<p>dfdf</p>
</div>
);

Why my components inside the map runs twice even though just before of map it runs single time

The map function produces the < PricedLayout /> component twice. I don't understand why it occurs, so I assumed that it might be because my map function was called twice, but that isn't the case since I can see a single printing of "testing" right before the map function.
const FreeAndMegaTestSeries = (props) => {
return (
<div className={styles.main}>
<div className={styles.right}>
<p className={styles.mainHeading}>Mega Test Series</p>
<Slider
arrows={true}
slidesToShow={3}
slidesToScroll={2}
autoplay={false}
infinite={true}
prevArrow={<img src={leftarrow} alt="left arrow" />}
nextArrow={<img src={rightarrow} alt="right arrow" />}
>
{console.log("testing")}
{props.priced.length &&
props.priced.map((p, i) => {
return <PricedLayout p={p} i={i}/>
})}
</Slider>
</div>
</div>
);
};
export default FreeAndMegaTestSeries;
////////////////////////////PricedLaout////////////////////////
const PricedLayout = (props) => {
const p=props.p;
const i=props.i;
return (
<>
<div className={styles.slider}>
<div className={styles.container} key={i}>
<div className={styles.enroll}>1.2k students enrolled</div>
</div>
</div>
</>
);
};
export default PricedLayout;

Dynamic nested accordion with nested children

I am trying to build a reusable accordion, i was able to create an accordion with one level, but here i am stuck to have the nested accordion.
What i have tried so far
App.js
import "./styles.css";
import Accordion from "./Accordion";
import LIST from './Constants';
const listMaker = (item) => {
let faqItem;
if (item.children.length === 0) {
faqItem = (
<>
<Accordion title={item.name}></Accordion> <hr />
</>
);
} else {
let faqItemChildren = item.children.map((item) => {
let faqItem = listMaker(item);
return (
<>
${faqItem}
<hr />
</>
);
});
faqItem = <Accordion title={item.name}>{faqItemChildren}</Accordion>;
}
return faqItem;
};
let listItems = LIST.map((item) => {
let menuItem = listMaker(item);
return menuItem;
});
export default function App() {
return listItems;
}
have added codesandbox
I am new tor react, Any help is appreciated
Instead of using dangerouslySetInnerHTML you can use the children, as you need is a spread of React.ReactChildren. That would be just calling the {children} from props instead of the dangerouslySetInnerHTML
<div className="accordion__section">
<button className={`accordion ${setActive}`} onClick={toggleAccordion}>
<p className="accordion__title">{title}</p>
<Chevron className={`${setRotate}`} width={10} fill={"#777"} />
</button>
<div
ref={content}
style={{ maxHeight: `${setHeight}` }}
className="accordion__content"
>
{children}
</div>
</div>
Here is a forked solution of your codesandbox.
Also, Instead of setting the DOM to a variable, as its a conditional scenario, you can use the ternary operator, which helps in better readability.
const listMaker = (item) => {
return (
<>
{item.children.length === 0 ? (
<Accordion title={item.name} />
) : (
<Accordion title={item.name}>
{item.children.map((childItem) => {
return listMaker(childItem);
})}
</Accordion>
)}
</>
);
};
dangerouslySetInnerHTML is to use with strings. You shouldn't give an array of components to it. Yet you don't send any prop called content anyway. I think you meant children prop there. Just render children instead of using dangerouslySetInnerHTML
In your Accordion component replace this:
<div
className="accordion__text"
dangerouslySetInnerHTML={{ __html: props.content }}
/>
With this:
<div className="accordion__text">
{ props.children }
</div>

looping over two arrays in react

So i have two map() blocks and 1st block is part of 2nd one, but i dont want 1st map() to affect 2nd one. How to accomplish that?
I'm new in JS and React. Thank you!
const Ciklogen = () => {
links.map((h) => {
console.log(h.heading, h.text, h.url)
return (
<>
<h3 className='heading'>{h.heading}</h3>
<p className='kratak-opis'>{h.text}</p>
<a href={h.url}>
<button className='read-more'>Read more</button>
</a>
</>
)
})
return (
<>
<Navigation logo={logo} links={links} />
{cssClass.map((style) => {
return (
<div key={style.id} className={`bg-image ${style.name}`}>
<div className='bg-text'>{ **1st block should be here**} </div>
</div>
)
})}
</>
)
}
export default Ciklogen

Why I can't call useRef inside callback?

When I write this code I have an error:
React Hook "useRef" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function
What should I do with this code?
return ITEMS.map((item, i) => {
const elementRef = useRef(null);
return (
<div
ref={elementRef}
key={i}
>
<p>{item.name}</p>
<Wrapper>
{item.name === visibleItem && (
<Item
parentRef={elementRef}
/>
)}
</Wrapper>
</div>
);
}
Here are two possibilities, Either using useRef with an object/array, or using createRef as suggested by Yevgen Gorbunkov.
I'm not entirely sure as to the viability of these as the createRef option will create entirely new refs on each render, and the useRef option you'll need to make sure your keys/indexes are always the same.
const ITEMS = [{ name: "test" }, { name: "test2" }];
export default function App() {
const ref = useRef({});
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
{ITEMS.map((item, idx) => {
return (
<div key={idx} ref={element => (ref.current[idx] = element)}>
<p>{item.name}</p>
<Wrapper>
{item.name === visibleItem && (
<Item parentRef={ref.current[idx]} />
)}
</Wrapper>
</div>
);
})}
{ITEMS.map((item, idx) => {
const ref = createRef();
return (
<div key={idx} ref={ref}>
<p>{item.name}</p>
<Wrapper>
{item.name === visibleItem && <Item parentRef={ref} />}
</Wrapper>
</div>
);
})}
</div>
);
}

Categories

Resources