Meteor + React + createcontainer - reactjs

Using react with meteor here, I have main component called App, and it wraps page layout (Header, Sidebar, Right-sidebar).
export default class App extends Component {
render() {
return (
<div>
<nav className="navigation">
<Header />
<Sidebar />
</nav>
<div className="content">
<Subnavbar />
<div className="container">
{this.props.children}
</div>
</div>
<Rightsidebar />
</div>
);
}
};
I'm trying to setup authentication system using Meteor's built in auth system. using "accounts-password" package.
To my knowldge, I need to use createContainer from 'meteor/react-meteor-data' to inject auth params to components.
Similar to this example:
import { createContainer } from 'meteor/react-meteor-data';
import MainPage from '../pages/MainPage.jsx'
export default MainContainer = createContainer(({params}) => {
const currentUser = Meteor.user();
return {
currentUser,
};
}, MainPage);
However in the above example, it only injects the parms to a single component, how can I go about injecting auth info to all components in my app (Header, Sidebars ..etc)
Your help is highly appreciated.
Thank you

If you wrap App in createContainer, then App will have a prop currentUser. It can then be the responsibility of App to pass the currentUser prop to all of your components. If you find yourself passing around currentUser far too much, then you can wrap only the components that need currentUser in createContainer.
In that case you would have HeaderContainer, SidebarContainer, etc, each being wrapped with createContainer.

Related

How to implement Server Sider Rendering (SSR) for a NextJS component?

I want to implement Server Sider Rending SSR for a NextJS Typescript component. It's possible to do SSR for a page using getServerSideProps but not found any way for non page child components. It works fine under page folder but no luck outside of page components.
Say I have created a component with API under components folder, here getServerSideProps is not working and even SSR also not working. and can't see the content in page view source DOM.
/components/user.tsx
import React from 'react';
import {useEffect,useState} from 'react';
interface User {
id:number;
name: string;
username: string;
email:string;
}
const Users = () => {
const [data,setData]= useState([])
useEffect(()=>{
fetch("https://jsonplaceholder.typicode.com/users").then((result)=>{
result.json().then((resp)=>{
setData(resp);
})
})
},[])
console.log(data)
return (
<div>
<ul>
{data.map((data: User)=>
<li key={data.id}>
<h2>{data.name}</h2>
<h3>{data.username}</h3>
<h4>{data.email}</h4>
</li>
)}
</ul>
</div>
)
}
export default Users
/pages/user.tsx
import React from 'react';
import Users from "../components/Users";
function user() {
return (
<section>
<h1>User - Component</h1>
<main>
<Users />
</main>
</section>
);
};
export default user;
Can you please help how to implement SSR for components which located out side of pages folder?
As it notes in the documentation
getServerSideProps can only be exported from a page. You can’t export it from non-page files.
This rules out getServerSideProps, now for the ask itself
Two options
setup a corresponding pages/component page
Setup a custom server and use the following in next.config.js - This allows routing to be on you without using the pages as the only place things get served from.
module.exports = {
useFileSystemPublicRoutes: false,
}

React tailwind, cannot pass tailwind css from parent to child

I am running into a simple issue that doesn't seem to have an answer on quick google search or Tailwind doc.
I am a Vuejs user but I have started learning React. I have opted to use TailwindCSS for testing my React application but I noticed there is some differences of Tailwind usage between Vuejs and React.
In Vue, I can control a child component via the parent component like so:
Parent component:
<template>
<div class="w-screen">
<ChildComponent class="w-1/2 mx-auto" />
</div>
</template>
With the child being able to centre on screen through the above parent component as should in the ChildComponent's class.
However, when I tried to do the same in React like so:
Parent component:
import Homepage from './views/Homepage';
function App() {
return (
<div className='bg-black w-screen'>
<Homepage className="w-1/2 mx-auto"/>
</div>
);
}
export default App;
Nothin happens when I placed the CSS at the Homepage child component from the parent.
I am sure there is a simple answer but I wasn't about to search the doc or use any keywords to find this problem. Anyone got a hint or confirm this is intended in React or have I done something wrong with the installation?
This is less of a Tailwind question and more of a React question. You cannot use className on the Homepage component without passing it as a prop. In your case, Homepage is not expecting any className. So while making your Homepage component you have to provide a prop called 'className' then it will work fine.
Or if you simply use a div in place of Homepage it will work normally. Have a look at this codesandbox link
You need to consider that <Homepage/> is a React component and cannot accept HTMLAttrs just like that.
this example might clear it:
const app = () => {
<div className="bg-black">
<Homepage className="bg-red" />
</div>
}
const homePage = (props) => {
<div className={props.className}>
<h1 className="bg-red">hi</h1>
</div>
}
the className that you pass to <Homepage/> is actually a props rather than Html attribure.
In Vue it's fairly straightforward but in react you need to be explicit and use className in your component
// Creating component
const Button = ({ className, children }) => {
return <button className={`${className} bg-red-500`}>{children}</button>
}
export default Button
// Using component
<Button className="text-white">MyButton</Button>
import Homepage from './views/Homepage';
function App() {
return (
<div className='bg-black w-screen'>
<Homepage className="w-1/2 mx-auto"/>
</div>
);
}
export default App;
views/Homepage
you have to receive props that are going to be passed as className
const homePage = ({className}) => {
<div className={className}>
<h1 className="bg-red">hi</h1>
</div>
}
export default homePage
then export your component

Have a common header layout in nextjs

I have 2 pages user.js and nonuser.js and one component header. user.js and nonuser.js have same functionality with slight changes in UI. Now I want to integrate all this. Like when I visit the page by default table of user.js must be viewed. One click of nonuser.js it should change to the nonuser.js table. And I want header to be same for both, content in textbox should not change when I switch between pages.
I'm new to next.js and react
header.js
import React, { Component } from 'react';
import '../Header/header.css';
import { Menu, Input, Icon } from 'antd';
import Link from 'next/link';
class HeaderComponent extends Component {
render() {
return (
<div className="navbar">
<div className="header">
<div className="col-1">
<div className="menu">
<div>
<Link href="/User"><a>Users</a></Link>
</div>
<div>
<Link href="/nonUser"><a>Non Users</a></Link>
</div>
<Input className="text-box" placeholder="Enter name" prefix={<Icon type="search" ></Icon>}></Input>
</div>
</div>
</div>
</div>
)
}
}
export default HeaderComponent
user.js
class User extends Component {
render() {
return (
<React.Fragment>
<div className="ant-table-row">
<div className="table-head-text">
<span className="text">Users({data.length})</span>
<Pagination defaultCurrent={1} total={100} />
</div>
<Table
rowKey={data._id}
columns={this.columns1}
rowSelection={this.rowSelection}
onExpand={this.onExpand}
dataSource={data} />
</div>
</React.Fragment>
)
}
I didn't add nonuser component, its same as user component
index.js
import Header from '../components/Header/header';
import Layout from '../components/Layout';
function App() {
return (
<Header/>
<div>
</div>
)
}
export default App;
I've done this, On first landing the only header is there and on clicking user link in header, header disappears and only table of user is shown.
EDIT:
I tried this header appears in both and I placed a textbox in header .textbox value clears when I switch between pages.
user.js and nonuser.js
render(){
return(
<Layout>
<div>.....</div>
</Layout>
)
}
Also tried
index.js
render() {
return (
<Layout>
<div>
</div>
</Layout>
)
}
layout.js
const Layout = ({children}) => (
<div>
<Header></Header>
{children}
</div>
);
From what I make of your question, you want to use HeaderComponent as a common header for both pages? Then I'd suggest placing it in your components/Layout file. Next will wrap all pages in the layout component, thus adding your header to all pages.
I'm also wondering why you have an index.js file? Unless it's placed in pages/ folder, it isn't something you normally do in Next. The pages user.js and nonuser.js should also be placed in the pages/ folder. Next will then automatically load the to files and provide them under the routes /user and /nonuser (based on the name of the file). This will also make Next wrap each page in the layout component mentioned above.
I'd suggest looking into NextJS learning guide. It provides a very good introduction to NextJS and will make it a lot easier to use NextJS if you. They have a lesson explaining how to use Shared Components which explains exactly what you seem to be looking for.
Hope this helps a bit.
Edit:
Example using _app.js
The following is an example of how to use a custom layout component in next using _app.js. It's based on Nexts own example.
// components/Layout.js
import React, { Component } from 'react';
import Header from './Header';
class Layout extends Component {
render () {
const { children } = this.props
return (
<div className='layout'>
<Header />
{children}
</div>
);
}
}
// pages/_app.js
import React from 'react';
import App from 'next/app';
import Layout from '../components/Layout';
export default class MyApp extends App {
render () {
const { Component, pageProps } = this.props
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
}
To get more information on how to make use of _app.js properly, check out their documentation on custom app.

how can I dynamically attach sidebar components to multiple instances of sidebar?

I'm new to React and building out a design a ran into a problem.
I have a component called SideBar. I am using this component two times, one on each side of the page.
The problem is that I would like to add different components to each instance of the SideBar component. These would be lists of various items and etc. I assumed I could next component tags but the sidebar component doesn't output.
import React, { Component } from "react";
import SideBar from "./WorkspaceComponents/SideBar";
import ScrollerBox from "./WorkspaceComponents/SideBarComponents/ScrollerBox";
class Workspace extends Component {
render() {
return (
<main className="reely-workspace">
<SideBar position="SideBarLeft">
<ScrollerBox />
</SideBar>
<SideBar position="SideBarRight" />
</main>
);
}
}
export default Workspace;
Your sidebar component should receive a children prop and render it out.
Something like this:
class Sidebar extends Component {
render() {
const {children} = this.props;
return (
<div className="sidebar">
<h1>Sidebar</h1>
{children}
</div>
)
}
}
Check out this post on react docs to understand how to compose react components: https://reactjs.org/docs/composition-vs-inheritance.html
You can make your SideBar Component a wrapper component which wraps around the content given in it.
Making SideBar Component a Wrapper Component :
class Sidebar extends Component {
render() {
return (
<div className="sidebar">
// You can add any custom element here //
{this.props.children}
</div>
)
}
}
All your element passed inside the SideBar Component will now be rendered as a part of SideBar along with what it contains.
Way to consume the wrapper component:
<SideBar>
<Content1></Content1>
<Content2></Content2>
<Content3></Content3>
</SideBar>

React: Is it bad practice to import a child component directly rather than pass in as a dependency?

I may be over thinking this, but I am curious if importing a child component directly is bad practice with regards to coupling and testing.
Below is a simple example:
import Header from './header.jsx';
class Widget extends React.Component {
render() {
return (
<div>
<Header></Header>
<div>{this.props.importantContent}</div>
</div>
)
}
}
To me it looks like there is now coupling between Widget and Header. With regards to testing, I don't see an easy way to mock the Header component when testing the Widget component.
How do other larger React apps handle cases like this? Should I pass Header in as a prop? If using react-redux, I can inject header with the Connect method like below to reduce boilerplate. Is that sound?
import { connect } from 'react-redux';
import Header from './header.jsx';
class Widget extends React.Component {
render() {
return (
<div>
{this.props.header}
<div>{this.props.importantContent}</div>
</div>
)
}
}
const mapStateToProps = state => {
return {
header: Header
}
}
export default connect(mapStateToProps)(Widget)
I am interested is simple doing what the community is generally doing. I see that one solution is doing shallow rendering to test on the main part of the component and not the child components using something like Enzyme.
Thoughts or other ideas?
Passing elements / components as props is a good idea. Having default props is a good idea too:
const Widget = ({
header = <div>Default Header.. </div>,
content = <div>Default Content.. </div>
}) =>
<div>
{header}
{content}
</div>
Then elsewhere in your app:
<Widget header={<Header title="Foo" />} content="content from props" />
No need to inject using connect
You can also pass a component, not just an element if you want to interact with props / send data back to parent:
const Widget = ({
Header = props => <div>Default Header.. </div>,
Content = props => <div>Default Content.. </div>
}) =>
<div>
<Header />
<Content />
</div>
Elsewhere:
<Widget Header={Header} Content={props => <Content />} />
As long as the component always renders the same thing it can be directly rendered as a child rather than the parent.
If all other portions of the Component remain constant and only the Header can be different across pages then you could actually implement it as an HOC instead of passing it as a props
const MyCompFactory = ({CustomHeader = DefaultHeader}) => {
return class Widget extends React.Component {
render() {
return (
<div>
<CustomHeader/>
<div>{this.props.importantContent}</div>
</div>
)
}
}
}
and use it like
const CustomComponent = MyCompFactory({CustomComponent: Header})
as long as testing is concerned in your case, you could just shallow render your component and then Search if the Header component is rendered something like
import Header from 'path/to/header'
const component = shallow(
<Widget {...customProps}/>
)
test('test' , () => {
expect(component.find(Header).exists()).toBe(true)
})

Resources