Resolve Nextjs URL to a selected component - javascript

From what I understand Nextjs resolves URLs by mapping them to their respective file in pages folder. So pages/about-us.js will be accessable via href="/about-us".
I want to create multiple languages but don't wanna duplicate the necessary components/JS files. So assuming I have an about-us.js with following content:
<Head title={meta}/>
<Nav/>
<MainContent language={lang}/>
<Footer/>
How can I map /pl/about-us to the /about-us.js in the root of pages without creating another about-us.js in /pages/pl/..?

One of the solution I can think of is to pass the language as a query param
Example
// code for page/about-us.js page
import { withRouter } from 'next/router';
const AboutUs = ({ router }) => {
const { lang } = router.query;
return <div>Welcome to next.js! Language = {lang}</div>;
};
export default withRouter(AboutUs);
so If you got to about-us?lang=pl it will show
Welcome to next.js! Language = pl
Or instead of parsing language inside every page, you can use custom app.js with the code something like this
// custom _app.js
import React from 'react'
import App, { Container } from 'next/app'
export default class MyApp extends App {
static async getInitialProps({ Component, router, ctx }) {
let pageProps = {}
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx)
}
return { pageProps }
}
state = {
language: undefined
};
componentDidMount() {
const { router } = this.props;
this.setState({ language: router.query.lang });
}
render () {
const { Component, pageProps } = this.props
return (
<Container>
<Component {...pageProps} language={this.state.langugage} />
</Container>
)
}
}
so every page will have language passed as a param.
Hope this helps.
UPDATE:
to make a custom routing you need to check disabling file-system routing and write some custom server routing

Related

Using client-only routes with page templates coming from Contentful

Goal
I am looking to use client-only routes for content under a certain URL (/dashboard). Some of this content will be coming from Contentful and using a page template. An example of this route would be {MYDOMAIN}/dashboard/{SLUG_FROM_CONTENTFUL}. The purpose of this is to ensure projects I have worked on at an agency are not able to be crawled/accessed and are only visible to 'employers' once logged in.
What I have tried
My pages are generated via gatsby-node.js. The way of adding authentication/client-only routes has been taken from this example. Now the basics of it have been setup and working fine, from what I can tell. But the private routes seem to only work in the following cases:
If I'm logged in and navigate to /dashboard
I'm shown Profile.js
If I an not logged in and go to /dashboard
I'm shown Login.js
So that all seems to be fine. The issue comes about when I go to /dashboard/url-from-contentful and I am not logged in. I am served the page instead of being sent to /dashboard/login.
exports.createPages = async ({graphql, actions}) => {
const { createPage } = actions;
const { data } = await graphql(`
query {
agency: allContentfulAgency {
edges {
node {
slug
}
}
}
}
`);
data.agency.edges.forEach(({ node }) => {
createPage({
path: `dashboard/${node.slug}`,
component: path.resolve("src/templates/agency-template.js"),
context: {
slug: node.slug,
},
});
});
}
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions;
if(page.path.match(/^\/dashboard/)) {
page.matchPath = "/dashboard/*";
createPage(page);
}
};
My auth.js is setup (the username and password are basic as I am still only developing this locally):
export const isBrowser = () => typeof window !== "undefined";
export const getUser = () =>
isBrowser() && window.localStorage.getItem("gatsbyUser")
? JSON.parse(window.localStorage.getItem("gatsbyUser"))
: {};
const setUser = (user) =>
window.localStorage.setItem("gatsbyUser", JSON.stringify(user));
export const handleLogin = ({ username, password }) => {
if (username === `john` && password === `pass`) {
return setUser({
username: `john`,
name: `Johnny`,
email: `johnny#example.org`,
});
}
return false;
};
export const isLoggedIn = () => {
const user = getUser();
return !!user.username;
};
export const logout = (callback) => {
setUser({});
call
};
PrivateRoute.js is setup the following way:
import React from "react";
import { navigate } from "gatsby";
import { isLoggedIn } from "../services/auth";
const PrivateRoute = ({ component: Component, location, ...rest }) => {
if (!isLoggedIn() && location.pathname !== `/dashboard/login`) {
navigate("/dashboard/login");
return null;
}
return <Component {...rest} />;
};
export default PrivateRoute;
dashboard.js has the following. The line <PrivateRoute path="/dashboard/url-from-contentful" component={Agency} />, I have tried a couple of things here - Statically typing the route and using the exact prop, using route parameters such as /:id, /:path, /:slug :
import React from "react";
import { Router } from "#reach/router";
import Layout from "../components/Layout";
import Profile from "../components/Profile";
import Login from "../components/Login";
import PrivateRoute from "../components/PrivateRoute";
import Agency from "../templates/agency-template";
const App = () => (
<Layout>
<Router>
<PrivateRoute path="/dashboard/url-from-contentful" component={Agency} />
<PrivateRoute path="/dashboard/profile" component={Profile} />
<PrivateRoute path="/dashboard" />
<Login path="/dashboard/login" />
</Router>
</Layout>
);
export default App;
And finally agency-template.js
import React from "react";
import { graphql, Link } from "gatsby";
import styled from "styled-components";
import SEO from "../components/SEO";
import Layout from "../components/Layout";
import Gallery from "../components/Gallery";
import GeneralContent from "../components/GeneralContent/GeneralContent";
const agencyTemplate = ({ data }) => {
const {
name,
excerpt,
richDescription,
richDescription: { raw },
images,
technology,
website,
} = data.agency;
const [mainImage, ...projectImages] = images;
return (
<>
<SEO title={name} description={excerpt} />
<Layout>
<div className="container__body">
<GeneralContent title={name} />
<Gallery mainImage={mainImage} />
<GeneralContent title="Project Details" content={richDescription} />
<div className="standard__images">
<Gallery projectImages={projectImages} />
</div>
<ViewWebsite>
<Link className="btn" to={website}>
View the website
</Link>
</ViewWebsite>
</div>
</Layout>
</>
);
};
export const query = graphql`
query ($slug: String!) {
agency: contentfulAgency(slug: { eq: $slug }) {
name
excerpt
technology
website
images {
description
gatsbyImageData(
layout: FULL_WIDTH
placeholder: TRACED_SVG
formats: [AUTO, WEBP]
quality: 90
)
}
richDescription {
raw
}
}
}
`;
export default agencyTemplate;
I assume that gating content from a CMS is possible with Gatsby but I might be wrong given it is an SSG. I may be misunderstanding the fundamentals of client-only. The concepts in React and using Gatsby are still very new to me so any help or guidance in achieving the goal would be appreciated.
What I ended up doing
So the answer I marked was the one that 'got the ball rolling'. The explanation of what was happening with state and requiring either useContext or redux helped me understand where I was going wrong.
Also, the suggestion to use web tokens prompted me to find more information on using Auth0 with the application.
Once I had got out of the mindset of creating pages using Gatsby (Through a template, via gatsby-node.s), and instead doing it in a 'React way' (I know Gatsby is built with React) by handling the routing and GraphQL it became clearer. Along with the authentication, all I ended up doing was creating a new <Agency /> component and feeding the data from GraphQL into it and updating the path with my map().
return (
<>
<Router>
<DashboardArea path="/dashboard/" user={user} />
{agencyData.map(({ node }, index) =>
node.slug ? (
<Agency key={index} data={node} path={`/dashboard/${node.slug}`} />
) : null
)}
</Router>
</>
);
I assume that in your PrivateRoute component, you're using the isLoggedIn check incorrectly. importing and using isLoggedIn from auth.js will run only initially and will not act as a listner. What you can do is that store the value of isLoggedin in global state variable like(useContext or redux) and make a custom hook to check for the login state. Secondly avoid accessing localStorage directly, instead use the global state managment (useContext, redux) or local state managment (useState, this.state).
Note: that when ever you go to a route by directly pasting url in browser, it always refreshes the page and all your stored state is reinitialized. This may be the reason why you may be experiencing this issue. The browser does not know that you had been previously logged in and therefore it always validates once your application is mounted. What you can do is that you can store isLoggedIn state in browser's localstore. Personally I like to use redux-persist for that.
export const useGetUser = () => { //add use infront to make a custom hook
return useSelector(state => state.gatsByUser) // access user info from redux store
};
export const handleLogin = ({ username, password }) => {
//suggestion: don't validate password on client side or simply don't use password,
//instead use tokens for validation on client side
if (username === `john` && password === `pass`) {
dispatch(setUserInfo({
username: `john`,
name: `Johnny`,
email: `johnny#example.org`,
isLoggedIn: true,
}));
return true;
}
return false;
};
// adding 'use' infront to make it a custom hook
export const useIsLoggedIn = () => {
//this will act as a listner when ever the state changes
return useSelector(state => state.gatsByUser?.isLoggedIn ?? false);
};
export const logout = (callback) => {
const dispatch = useDispatch(); // redux
dispatch(clearUserInfo());
};
Now in private route do
import React from "react";
import { navigate } from "gatsby";
import { useIsLoggedIn } from "../services/auth";
const PrivateRoute = ({ component: Component, location, ...rest }) => {
const isLoggedIn = useIsLoggedIn();
if (!isLoggedIn) {
return navigate("/dashboard/login");
}
return <Component {...rest} />;
};
export default PrivateRoute;
It looks like you're server-side rendering dashboard/[url] in gatsby-node.js/createPages()? IIRC those routes will have higher precedence than dynamic routes (which you specify with #reach/router in dashboard.js).
Plus, the content of those routes are currently publicly available. If you want to keep them truly private, you should query Contentful graphql API directly on the client side (via fetch() or use apollo client, urql, etc.), instead of relying on Gatsby's graphql server.
I would do the follows:
Removing the dashboard/[url] portion in your gatsby-node.js
Configure your web host so that all routes matches '/dashboard/*' will redirect to '/dashboard'
If you happen to host your static site on Netlify, you'd create a _redirects with this, assuming you configure Gatsby to create nice url:
# /static/_redirect
/dashboard/* /dashboard 200
A possible simpler way that match your current setup is gating content at web host level. You can configure nginx to protect /dasboard/* with basic auth. However maintaining/updating password is a pain & modern hosting solution don't really allow user to configure that.
Netlify offers its own authentication solution that you could look into.
I've had the same issue earlier and I couldn't get exact functionality with Private Routes.
In my case, I created two separate Layouts for Public and Private Routes and built the authentication to Private Layout. Logged-in user data were linked to a redux store (First I used Context, then moved to Redux). In Private routes with the Private Layout, it redirected the guest users to the Login page and redirected them to the same page after login.
Private layout is something like this:
import React from "react";
import { navigate } from "gatsby";
import { useSelector } from "react-redux";
const PrivateLayout = ({children}) => {
const isLoggedIn = useSelector(state => state.user.isLoggedIn);
useEffect(() => {
if (!isLoggedIn) {
// redirect the user to login page.
// I'm sending the current page's URL as the redirect URL
// so that I can take the user back to this page after logging in.
}
}, [isLoggedIn])
if (!isLoggedIn) return null;
return <>
{...header}
{children}
{...footer}
</>
}
export default PrivateLayout;
Not sure if this workaround suits you. If it does, I can give you more info.

Render HTML for conditional routes in Next Js

I am trying to figure out, why my HTML is not rendering for conditional routes, actually, I have three components, one is parent index.js inside slug directory and two are child components country.js, profile.js inside components directory.
I want to keep same URL pattern for country and profile component
domain.com/[countryCode] or domain.com/[profileUsername]
Please have a look at the code below.
index.js
import React from 'react'
import { withRouter } from 'next/router'
import Country from '../../components/Country'
import Details from '../../components/Details'
class Type extends React.Component {
constructor(props){
super(props)
this.state = {
isCountry: ''
}
}
checkCountry = (type) => {
let isCountry = ''
if(type){
const countries = JSON.parse(localStorage.getItem('countries'))
let countryCodes = []
isCountry = countries.map(item => item.country.toLowerCase()).includes(type)
this.setState({isCountry:isCountry})
}
}
componentDidUpdate(prevProps){
if(this.props.router.query.slug !== prevProps.router.query.slug){
this.checkCountry(this.props.router.query.slug)
}
}
componentDidMount(){
this.checkCountry(this.props.router.query.slug)
}
render() {
const {isCountry} = this.state
return (
<React.Fragment>
{isCountry ? (
<Country/>
) : (
<Details/>
)}
</React.Fragment>
)
}
}
the above code is working fine as expected, but the problem is, It is not returning HTML into the view source code. Please suggest how can I sort out the above issue
You should use getStaticProps to provide next.js information about your request to API so next.js could cache your API responses (or similar functions, find what you need in the documentation: https://nextjs.org/docs/advanced-features/automatic-static-optimization).
Could be useful: https://nextjs.org/docs/advanced-features/static-html-export.

React: Array.reduce + Object.assign for dynamic hookrouter routes complains re: PascalCase [duplicate]

I am trying to dynamically render components based on their type.
For example:
var type = "Example";
var ComponentName = type + "Component";
return <ComponentName />;
// Returns <examplecomponent /> instead of <ExampleComponent />
I tried the solution proposed here React/JSX dynamic component names
That gave me an error when compiling (using browserify for gulp). It expected XML where I was using an array syntax.
I could solve this by creating a method for every component:
newExampleComponent() {
return <ExampleComponent />;
}
newComponent(type) {
return this["new" + type + "Component"]();
}
But that would mean a new method for every component I create. There must be a more elegant solution to this problem.
I am very open to suggestions.
EDIT:
As pointed out by gmfvpereira these days there is an official documentation entry for this:
https://reactjs.org/docs/jsx-in-depth.html#choosing-the-type-at-runtime
<MyComponent /> compiles to React.createElement(MyComponent, {}), which expects a string (HTML tag) or a function (ReactClass) as first parameter.
You could just store your component class in a variable with a name that starts with an uppercase letter. See HTML tags vs React Components.
var MyComponent = Components[type + "Component"];
return <MyComponent />;
compiles to
var MyComponent = Components[type + "Component"];
return React.createElement(MyComponent, {});
There is an official documentation about how to handle such situations is available here: https://facebook.github.io/react/docs/jsx-in-depth.html#choosing-the-type-at-runtime
Basically it says:
Wrong:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Wrong! JSX type can't be an expression.
return <components[props.storyType] story={props.story} />;
}
Correct:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Correct! JSX type can be a capitalized variable.
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}
There should be a container that maps component names to all components that are supposed to be used dynamically. Component classes should be registered in a container because in modular environment there's otherwise no single place where they could be accessed. Component classes cannot be identified by their names without specifying them explicitly because function name is minified in production.
Component map
It can be plain object:
class Foo extends React.Component { ... }
...
const componentsMap = { Foo, Bar };
...
const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;
Or Map instance:
const componentsMap = new Map([[Foo, Foo], [Bar, Bar]]);
...
const DynamicComponent = componentsMap.get(componentName);
Plain object is more suitable because it benefits from property shorthand.
Barrel module
A barrel module with named exports can act as such map:
// Foo.js
export class Foo extends React.Component { ... }
// dynamic-components.js
export * from './Foo';
export * from './Bar';
// some module that uses dynamic component
import * as componentsMap from './dynamic-components';
const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;
This works well with one class per module code style.
Decorator
Decorators can be used with class components for syntactic sugar, this still requires to specify class names explicitly and register them in a map:
const componentsMap = {};
function dynamic(Component) {
if (!Component.displayName)
throw new Error('no name');
componentsMap[Component.displayName] = Component;
return Component;
}
...
#dynamic
class Foo extends React.Component {
static displayName = 'Foo'
...
}
A decorator can be used as higher-order component with functional components:
const Bar = props => ...;
Bar.displayName = 'Bar';
export default dynamic(Bar);
The use of non-standard displayName instead of random property also benefits debugging.
With the introduction of React.lazy, we can now use a true dynamic approach to import the component and render it.
import React, { lazy, Suspense } from 'react';
const App = ({ componentName, ...props }) => {
const DynamicComponent = lazy(() => import(`./${componentName}`));
return (
<Suspense fallback={<div>Loading...</div>}>
<DynamicComponent {...props} />
</Suspense>
);
};
This approach makes some assumptions about the file hierarchy of course and can make the code easy to break.
I figured out a new solution. Do note that I am using ES6 modules so I am requiring the class. You could also define a new React class instead.
var components = {
example: React.createFactory( require('./ExampleComponent') )
};
var type = "example";
newComponent() {
return components[type]({ attribute: "value" });
}
For a wrapper component, a simple solution would be to just use React.createElement directly (using ES6).
import RaisedButton from 'mui/RaisedButton'
import FlatButton from 'mui/FlatButton'
import IconButton from 'mui/IconButton'
class Button extends React.Component {
render() {
const { type, ...props } = this.props
let button = null
switch (type) {
case 'flat': button = FlatButton
break
case 'icon': button = IconButton
break
default: button = RaisedButton
break
}
return (
React.createElement(button, { ...props, disableTouchRipple: true, disableFocusRipple: true })
)
}
}
Across all options with component maps I haven't found the simplest way to define the map using ES6 short syntax:
import React from 'react'
import { PhotoStory, VideoStory } from './stories'
const components = {
PhotoStory,
VideoStory,
}
function Story(props) {
//given that props.story contains 'PhotoStory' or 'VideoStory'
const SpecificStory = components[props.story]
return <SpecificStory/>
}
If your components are global you can simply do:
var nameOfComponent = "SomeComponent";
React.createElement(window[nameOfComponent], {});
Having a map doesn't look good at all with a large amount of components. I'm actually surprised that no one has suggested something like this:
var componentName = "StringThatContainsComponentName";
const importedComponentModule = require("path/to/component/" + componentName).default;
return React.createElement(importedComponentModule);
This one has really helped me when I needed to render a pretty large amount of components loaded in a form of json array.
Assume we have a flag, no different from the state or props:
import ComponentOne from './ComponentOne';
import ComponentTwo from './ComponentTwo';
~~~
const Compo = flag ? ComponentOne : ComponentTwo;
~~~
<Compo someProp={someValue} />
With flag Compo fill with one of ComponentOne or ComponentTwo and then the Compo can act like a React Component.
Assuming you are able to export * from components like so...
// src/components/index.js
export * from './Home'
export * from './Settings'
export * from './SiteList'
You can then re-import * into a new comps object, which can then be used to access your modules.
// src/components/DynamicLoader.js
import React from 'react'
import * as comps from 'components'
export default function ({component, defaultProps}) {
const DynamicComponent = comps[component]
return <DynamicComponent {...defaultProps} />
}
Just pass in a string value that identifies which component you want to paint, wherever you need to paint it.
<DynamicLoader component='Home' defaultProps={someProps} />
Suspose we wish to access various views with dynamic component loading.The following code gives a working example of how to accomplish this by using a string parsed from the search string of a url.
Lets assume we want to access a page 'snozberrys' with two unique views using these url paths:
'http://localhost:3000/snozberrys?aComponent'
and
'http://localhost:3000/snozberrys?bComponent'
we define our view's controller like this:
import React, { Component } from 'react';
import ReactDOM from 'react-dom'
import {
BrowserRouter as Router,
Route
} from 'react-router-dom'
import AComponent from './AComponent.js';
import CoBComponent sole from './BComponent.js';
const views = {
aComponent: <AComponent />,
console: <BComponent />
}
const View = (props) => {
let name = props.location.search.substr(1);
let view = views[name];
if(view == null) throw "View '" + name + "' is undefined";
return view;
}
class ViewManager extends Component {
render() {
return (
<Router>
<div>
<Route path='/' component={View}/>
</div>
</Router>
);
}
}
export default ViewManager
ReactDOM.render(<ViewManager />, document.getElementById('root'));
👍 You can create a reusable component with a fallback component.
export const StringComponent = (Base, { name, Fallback = undefined, ...rest }) => {
const Component = Base[name];
// return fallback if the component doesn't exist
if (!Component) return <Fallback/>
return <Component {...rest}/>;
};
And call it like this:
import * as Pages from "../pages"
const routes = [
{path: "/", element: "Home" },
{path: "/about", element: "About" },
{path: "*", element: "NotFound" },
]
export function App(){
const Fallback = Pages.NotFound
// render each route using a string as name
return (
<div>
{
routes.map(page =>
StringComponent(Pages, { name: page.element, Fallback })
)
}
</div>
)
}
OBS: Imported Pages needs to be something like this:
import Home from "./home"
import About from "./about"
import NotFound from "./not-found"
export { Home, About, NotFound }
I used a bit different Approach, as we always know our actual components so i thought to apply switch case.
Also total no of component were around 7-8 in my case.
getSubComponent(name) {
let customProps = {
"prop1" :"",
"prop2":"",
"prop3":"",
"prop4":""
}
switch (name) {
case "Component1": return <Component1 {...this.props} {...customProps} />
case "Component2": return <Component2 {...this.props} {...customProps} />
case "component3": return <component3 {...this.props} {...customProps} />
}
}
Edit: Other answers are better, see comments.
I solved the same problem this way:
...
render : function () {
var componentToRender = 'component1Name';
var componentLookup = {
component1Name : (<Component1 />),
component2Name : (<Component2 />),
...
};
return (<div>
{componentLookup[componentToRender]}
</div>);
}
...

Reach router navigate updates URL but not component

I'm trying to get Reach Router to navigate programmatically from one of my components. The URL is updated as expected however the route is not rendered and if I look at the React developer tools I can see the original component is listed as being displayed.
If I refresh the page once at the new URL then it renders correctly.
How can I get it to render the new route?
A simplified example is shown below and I'm using #reach/router#1.2.1 (it may also be salient that I'm using Redux).
import React from 'react';
import { navigate } from '#reach/router';
const ExampleComponent = props => {
navigate('/a/different/url');
return <div />;
};
export default ExampleComponent;
I was running into the same issue with a <NotFound defualt /> route component.
This would change the URL, but React itself didn't change:
import React from "react";
import { RouteComponentProps, navigate } from "#reach/router";
interface INotFoundProps extends RouteComponentProps {}
export const NotFound: React.FC<INotFoundProps> = props => {
// For that it's worth, neither of these worked
// as I would have expected
if (props.navigate !== undefined) {
props.navigate("/");
}
// ...or...
navigate("/", { replace: true });
return null;
};
This changes the URL and renders the new route as I would expect:
...
export const NotFound: React.FC<INotFoundProps> = props => {
React.useEffect(() => {
navigate("/", { replace: true });
}, []);
return null;
};
Could it be that you use #reach/router in combination with redux-first-history? Because I had the same issue and could solve it with the following configuration of my historyContext:
import { globalHistory } from "#reach/router";
// other imports
const historyContext = createReduxHistoryContext({
// your options...
reachGlobalHistory: globalHistory // <-- this option is the important one that fixed my issue
}
More on this in the README of redux-first-history
The same issue happens to me when I'm just starting to play around with Reach Router. Luckily, found the solution not long after.
Inside Reach Router documentation for navigate, it is stated that:
Navigate returns a promise so you can await it. It resolves after React is completely finished rendering the next screen, even with React Suspense.
Hence, use await navigate() work it for me.
import React, {useEffect} from 'react';
import {useStoreState} from "easy-peasy";
import {useNavigate} from "#reach/router";
export default function Home() {
const {isAuthenticated} = useStoreState(state => state.auth)
const navigate = useNavigate()
useEffect(()=> {
async function navigateToLogin() {
await navigate('login')
}
if (!isAuthenticated) {
navigateToLogin()
}
},[navigate,isAuthenticated])
return <div>Home page</div>
}
Try and use gatsby navigate. It uses reach-router. It solved my problem
import { navigate } from 'gatsby'

How to inject mobx store into a stateless component

I am using mobx and react in a web application and I want to find a way to pass mobx store state to a stateless component. Below is my current component source code:
import React from 'react';
import Panel from './Panel';
import {inject, observer} from 'mobx-react';
#inject(allStores => ({
form: allStores.store.form,
}))
#observer
export default class Creator extends React.Component {
connect() {
console.log(this.props.form);
};
render() {
return (
<Panel form={this.props.form} connect={this.connect.bind(this)}/>
);
}
};
How can I change it to be stateless? I tried below code but didn't work:
const Creator = ({form}) => {
const connect = ()=>{
console.log('xxxx,', form);
}
return (
<Panel form={form} connect={connect}/>
);
}
export default observer(Creator);
when I run above code, I got undefined value for form on the connect method. How can I inject the store into stateless component? I tried to use #inject on top of stateless component, but got a syntax error.
inject returns a function that you can use on a observer functional component:
var Example = inject("myStore")(observer((props) => {
// ...
}));
A variant of #Tholle answer :
const Example = inject("myStore")(observer(({myStore, otherProp}) => {
// ...
}));
const Example = inject(
'YOUR_STORE1',
'YOUR_STORE2'
)(
observer(({ YOUR_STORE1, YOUR_STORE2, OTHER_PROPS }) => {
return (
// Your Design
)
})
)
export default Example

Categories

Resources