We have a component <Book /> looks like following:
const Book = () => (<>
<Title />
<Thumbnail />
<Author />
</>)
And I want to give it a little change into this component, such looks like:
const CustomBook = () => (<>
<Title />
<h2>Hi, I am a subtitle</h2>
<Thumbnail>
<Author />
</>)
Let’s say new version of <Book /> is released:
const Book = () => (<>
<Title />
<Author /> {/* Position is changed *}
<Thumbnail /> {/* Position is changed *}
</>)
The position of <Author /> and <Thumbnail /> is now changed. But the <CustomBook /> doesn’t follow the structure of the new <Book /> since I wrote my own structure.
But what I actually wanted to do in the <CustomBook /> component was just appending an element after the <Title /> component.
Subsequently, one of my coworkers have suggested me the following approach:
<Book>
{builder => builder
// Assume that the keys are initially defined inside of the component
.appendAfter('title', <h2>Foobar</h2>)
.appendBefore(...)
.replace('foo', <Bar />)
.setProps('foo', { bar: 100 })
}
</Book>
But I don’t think it’s a good approach because:
1. The component is not self-descriptive.
2. The component is against React’s principals, that we should not manipulate the DOM directly. (Although it’s the virtual DOM)
I could define props such like afterTitle, but there are many components inside of the <Book /> component, therefore, it’s going to be hard to define all of the props. And we also should be able to remove or replace the elements.
I’m curious if there is a react-ish way to achieve this goal.
Thank you in advance.
(Edited)
TL;DR
Is there a way to append/replace/remove some component inside of a component, by an internally existing component, no matter how component internally changes, without defining props.
(Edited #2)
I'll publish the <Book /> component on NPM. So developers can't modify it. I want to allow developers to customize the component's internal DOM tree with such API as insertAfter('title', <Subtitle />). But not by props because I want to make it flexible.
If it is not necessary to have two separate components (one for <Book> and another <CustomBook>), then you can simply pass props to Book, for example, subtitle. Then in your Book component, you can check if it has a subtitle, and if so, display the subtitle. Ie,
const Book = () => (<>
<Title />
{ this.props.subtitle ? <h2>this.props.subtitle</h2> : null }
<Thumbnail />
<Author />
</>)
If you checked the reconciliation
1. Component instances are updated and reused based on their key.
2. React uses the key to match children in the original tree with children in the subsequent tree
Please provide key to each component and siblings elements
const CustomBook = () => (<>
<Title key={1}/>
<h2 key={2}>Hi, I am a subtitle</h2>
<Author key={3}/>
<Thumbnail key={4}/>
</>)
Note : for example purpose I have used 1,2,3.Please provide as per your requirements.
Related
First I apologize if this question has been answered elsewhere. I'm still learning.
Assuming we have a parent component that has children components inside of it, so :
in App.js:
<>
<Advertisement title="Free Shipping For Orders Above 150 USD ! " />
<NavBar />
<LandingSection />
<Featured />
<Explore />
<Shop />
<RecommendedVideos />
<AsSeenOn />
<Footer />
</>
Now, we all know that each component has it own css file, however, if I want to change specific CSS attributes/styles to fit with the new component and I just want it in this specific component, in our case it is App.js. What should I do ? any tutorials on this topic ?
Also ... What is the difference between using
import styles from './styles.css
className = {styles.someName}
and using
styled-components library ?
and most importantly, in professional/real-world apps, what method do developers use ?
Each component should use either css modules or styled component. That way style will be scoped to that component.
If you use plain css then it might clash with other components styles.
I have 3 components in nextjs and i want to achieve the below snippet in nextjs
<Route path="/" component={homePage} />
<Route path="/about" component={aboutPage} />
<Route path="/faq" component={faqPage} />
Q1. How can i do the same in nextjs without page refresh? (without react-router)
(Edit : some scholars are suggesting to read the docs but i have read it thoroughly and what i want is to pass a component along with the route)
Is this even possible in next js?
Q2: If i have url as /products?product_id=productid and on refresh if i want the url to be /products (basically i want to remove all params on refresh) What is the best practice to do this?
Thanks in advance
NextJS functions on a convention-based filesystem-based routing. You'd need to place your components in a directory structure that matches the routes you are wanting.
More details here:
https://nextjs.org/docs/routing/introduction
The Next.js docs don't really cover how to change away from <Route> components, however they have a lot of examples as code on how to do most things with Next.js. https://github.com/vercel/next.js/tree/canary/examples/layout-component
The below is what I used as an alternative to the component (there's no direct Next.js alternative).
_app.js
export default function MyApp({ Component, pageProps }) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout || ((page) => page)
return getLayout(<Component {...pageProps} />)
}
Any page:
import Layout from '../components/layout'
import Sidebar from '../components/sidebar'
export default function About() {
return (
<section>
<h2>Layout Example (About)</h2>
<p>
This example adds a property <code>getLayout</code> to your page,
allowing you to return a React component for the layout. This allows you
to define the layout on a per-page basis. Since we're returning a
function, we can have complex nested layouts if desired.
</p>
<p>
When navigating between pages, we want to persist page state (input
values, scroll position, etc) for a Single-Page Application (SPA)
experience.
</p>
<p>
This layout pattern will allow for state persistence because the React
component tree is persisted between page transitions. To preserve state,
we need to prevent the React component tree from being discarded between
page transitions.
</p>
<h3>Try It Out</h3>
<p>
To visualize this, try tying in the search input in the{' '}
<code>Sidebar</code> and then changing routes. You'll notice the input
state is persisted.
</p>
</section>
)
}
About.getLayout = function getLayout(page) {
return (
<Layout>
<Sidebar />
{page}
</Layout>
)
}
The main part for the layout that you want to wrap around the pages, components/layout.js:
import Head from 'next/head'
import styles from './layout.module.css'
export default function Layout({ children }) {
return (
<>
<Head>
<title>Layouts Example</title>
</Head>
<main className={styles.main}>{children}</main>
</>
)
}
What's happening is the _app.js wraps all pages inside the declared layout. Each page then defines what layout that page belongs to. The layout then accepts a page as the {children} prop object of which you can then render anywhere in your layout page.
Next uses filesystem based routing, your folder structure should look like
-- pages
-- index.js
-- about/index.js
-- faq/index.js
For the custom component part, make a component that's clickable, on click, use next builtin router to redirect
const router = useRouter();
router.push('/');
I'm new to React and I'm trying to figure out the purpose/use of <MyComponent></MyComponent> vs <MyComponent />. I can't seem to find information on anything except self-closing tags.
I've created a basic tab scroller as a JSFiddle using the self-closing <MyComponent /> and subsequent props, and I'm wondering if there's a better way to write in React than what I've done.
class TabScroller extends React.Component {
render() {
return (
<div className="tabScroller">
<div className="NavList">
<TabNav handleClick={this.handleNavClick} />
<TabList
tabs={this.state.tabs}
activeTab={this.state.activeTab}
scrollPosition={this.state.scrollPosition}
handleClick={this.handleTabClick}
/>
</div>
<TabContent content={this.state.tabs[this.state.activeTab].content} />
</div>
);
}
}
// ========================================
ReactDOM.render(
<TabScroller />,
document.getElementById('root')
);
In React's JSX, you only need to write <MyComponent></MyComponent> when the component has child components, like this:
<MyComponent>
<Child />
<Child />
<Child />
</MyComponent>
If there is nothing between <MyComponent> and </MyComponent>, then you can write it either <MyComponent/> or <MyComponent></MyComponent> (but <MyComponent/> is generally preferred). Details in Introducing JSX.
Just as a side note, you'd access those children in your component via the special props.children property. More in JSX in Depth: Children in JSX.
Note that this is very much not like HTML or XHTML. It's its own (similar) thing with different rules. For instance, in HTML, <div/> is exactly the same thing as <div>: A start tag, for which you must eventually have an end tag. Not so JSX (or XHTML). The rules for HTML are that void elements (elements that never have markup content, such as br or img) can be written with or without / before > and they never get an ending tag, but non-void elements (like div) must always have an ending tag (</div>), they cannot be self-closing. In JSX (and XHTML), they can be.
The purpose of self-closing tags is simply the fact that it is more compact. This is especially useful when said component doesn't have any children that you typically wrap around a parent.
So usually for leaf components (i.e compoents that do not have any children), you use the self-closing syntax. Like: <Component />. And even if it has props, you can do: <Component foo="bar" />.
However, remember that children is a prop, so you could technically do:
<Component children={<span>foo</span>} />
but I find it less readable and advise against it (read disclaimer below).
To summarize, these are equivalent:
<Component /> = <Component></Component>
<Component foo="bar" /> = <Component foo="bar"></Component>
<Component children={<span>foo</span>}></Component> =
<Component><span>foo</span></Component>
You can use whichever approach you prefer. Though praxis is to use the short-hand version when there are no children.
Disclaimer: While defining childen prop by its object key value will technically work, doing so is strongly discouraged as it disrupts the API as it is meant to be used. Use this version only if confident in what you are doing.
I encountered a problem in React that leaves me puzzled.
I want to create Component that's basically a wrapper around its children. Let's say a simple Button component.
<Button {...props} circular radius="small">
<Icon type="close" />
</Button>
When doing so I obtain the following error:
Cannot convert a Symbol value to a string
TypeError: Cannot convert a Symbol value to a string
at http://localhost:9009/static/preview.bundle.js:2027:45
at Array.map (native)
at objToCss (http://localhost:9009/static/preview.bundle.js:2025:30)
at http://localhost:9009/static/preview.bundle.js:2026:33
at Array.map (native)
at objToCss (http://localhost:9009/static/preview.bundle.js:2025:30)
at http://localhost:9009/static/preview.bundle.js:2050:42
at Array.reduce (native)
at flatten (http://localhost:9009/static/preview.bundle.js:2033:17)
at http://localhost:9009/static/preview.bundle.js:2045:63
Yet, and this is the crazy part, when I render more than one child, i.e. children, then it magically works.
<Button {...props} circular radius="small">
<Icon type="close" />
<Icon type="close" />
</Button>
=> no error
What in the world is going on? Why is React trying to convert my React element, which it first wraps into a symbol, into a string? What are Symbols anyways? If someone could enlighten me that would be awesome:) For now I render an empty <span /> to circumvent the problem.
i.e.
<Button {...props} circular radius="small">
<Icon type="close" />
<span />
</Button>
Right now this is my <Button /> component. I know I could directly export just the RawButton. But what I want to be doing later on is to compose components. Currently, I only get it to run by rendering at least 2 children. I do not understand how rendering a single child causes this problem-.-
const RawButton = styled.button`
border-radius: ${props => (props.circular ? '50%' : BORDER_RADIUS)};
`;
export default (props) =>
<RawButton {...props}>
<span />
{props.children}
</RawButton>
For example, I made a slider component in React that takes child components to make a category slider.
So, it is something like:
<Slider>
<Child someProps={this.props.someProps1} />
<Child someProps={this.props.someProps2} />
<Child someProps={this.props.someProps3} />
<Child someProps={this.props.someProps4} />
</Slider>
Is something like this possible in angular 1.5? I'm having a lot of trouble understanding angular components and it is not really ticking with me the way React does.
Thanks.