location.state fail with gatsby build - javascript

When I use the state with the gatsby component Link that work when I do test with gatsby develop but failded with gatsby build with an error about undefined stuff. The error message show by the terminal is WebpackError: TypeError: Cannot read property 'info' of undefined I try to check for undefined by two differents ways but that's don't work. I cannot figure what I must do to solve that's problem.
first test :
if (!location.state.info) {
return null
} else
second test
if (typeof location.state.info === `undefined`) {
return null
} else
index page
import React from "react"
import { Link } from "gatsby"
import Layout from "../components/layout"
const IndexPage = () => (
<Layout>
<Link to="/page_test/" state={{ info: "test" }}>
Test
</Link>
</Layout>
)
export default IndexPage
page
import React from "react"
import { Link } from "gatsby"
const TestPage = ({ location }) => {
return <div>{location.state.info}</div>
}
export default TestPage

What's undefined is location.state, not the info state itself. Changing your condition your code should work.
if (typeof location.state === `undefined`) {}
Here's some approach (same idea) using destructuring:
const TestPage = ({ location }) => {
const { state = {} } = location
const { info } = state
return info ? (
<div>{info}</div>
) : (
<div>Other content</div>
)
}
export default TestPage
Basically, with the destructuring, you are simplifying stuff. It's what you are using in ({ location }). By default, props are passed through pages and components in React so ({ location }) equals to (props) and then props.location. It's just a way of entering the nested properties of the object.
In the same way, once you have props.location (or location if destructured in props), you can:
const { state = {} } = location //equals to location.state
In the case above, you are destructuring plus setting a default value to empty ({}) if there's no state nested object in location.
In the same way:
const { info } = state //equals to state.info
If state is empty due to the previous destructuring, info will be empty as well, if not, it will take the value of state.info. So your return method can be a boolean condition such:
return info ? (
<div>{info}</div>
) : (
<div>Other content</div>
)

Related

Reading JSON file into React Context Provider with Typescript

My React Typescript app has a Context Provider DataProvider that is to read a value from a JSON file and provide it in the Context useData(). I am trying to do the read synchronously to avoid having to deal with a isLoading since this is a tiny local JSON file.
Is there a recommended way to read the JSON file synchronously inside a Context Provider?
I tried the following using node-sync, but its giving a Typescript error
Object is possibly 'undefined'.ts(2532)
on data at line
return data.find(...
Tried changing it to
return data?.find(...`
but now the error is
Property 'find' does not exist on type 'never'.ts(2339)
import React, {
createContext,
useContext,
Consumer,
Context,
ReactNode,
useMemo,
} from 'react';
import Sync from 'sync';
export interface DataProviderProps {
children: ReactNode;
}
export interface Data {
secretNumber?: string;
}
// #ts-ignore
const DataContext: Context<Data> = createContext<Data>();
export function DataProvider({ children }: DataProviderProps) {
const secretNumber = useMemo(() => {
// Read from JSON file
const contractFile =
process.env.REACT_APP_WORLD === 'main'
? '../main.json'
: '../test.json';
let data;
Sync(function () {
data = import(contractFile);
});
return data.find( // <=== TS error: Object is possibly 'undefined'. ts(2532)
({ name }: { name: string }) => name === 'elonmusk',
)?.secretNumber;
}, []);
const states = useMemo<Data>(() => {
return {
secretNumber,
};
}, [secretNumber]);
return (
<DataContext.Provider value={states}>
{children}
</DataContext.Provider>
);
}
export function useData(): Data {
return useContext(DataContext);
}
export const DataConsumer: Consumer<Data> = DataContext.Consumer;
array.find() returns undefined If no values satisfy the testing function, from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find, so just add (!) after the array.find()! fxn to ascertain a value would be returned.
sample code stub
data.find(todoCodeStubhere)!

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>);
}
...

How to get previous url in react gatsby

I am pretty much familiar with the React.js but new to Gatsby.
I want to detect the previous page URL in Gatsby?
You can pass down state using the Link component:
import React from 'react';
import { Link } from 'gatsby';
const PrevPage = () => (
<div>
<Link
to={`/nextpage`}
state={{ prevPath: location.pathname }}
>
Next Page
</Link>
</div>
)
const NextPage = (props) => (
<div>
<p>previous path is: {props.location.state.prevPath}</p>
</div>
);
Then you have access to prevPath from this.props.location.state in the next page.
Full credit to #soroushchehresa's answer — this answer is just extras built upon it.
Gatsby will throw error during production build, since location is not available during server-side rendering. You could get around it by checking for window object first:
class Page extends React.Component {
state = {
currentUrl: '',
}
componentDidMount() {
if (typeof window == 'undefined') return
this.setState({ currentUrl: window.location.href })
}
render() {
return (
<Link to="..." state={{ prevUrl: this.state.currentUrl }}>
)
}
}
But this requires us to implement this on every page, which is tedious. Gatsby has already set up #reach/router for server-side rendering, so we can hook into its location props. Only router components get that props, but we can use #reach/router's Location component to pass it to other components.
With that, we can write a custom Link component that always pass previous url in its state:
// ./src/components/link-with-prev-url.js
import React from 'react'
import { Location } from '#reach/router'
import { Link } from 'gatsby'
const LinkWithPrevUrl = ({ children, state, ...rest }) => (
<Location>
{({ location }) => (
//make sure user's state is not overwritten
<Link {...rest} state={{ prevUrl: location.href, ...state}}>
{ children }
</Link>
)}
</Location>
)
export { LinkWithPrevUrl as Link }
Then we can import our custom Link component instead of Gatsby's Link:
- import { Link } from 'gatsby'
+ import { Link } from './link-with-prev-url'
Now each Gatsby page component will get this previous url props:
const SomePage = ({ location }) => (
<div>previous path is {location.state.prevUrl}</div>
);
You might also consider creating a container that store state for the client side & use the wrapRootElement or wrapPageElement in both gatsby-ssr.js and gatsby-browser.js.
These answers are partially correct. If you set state using link api then the state persists in browser history.
So if you go from Page1 to Page2 then the eg the state.prevUrl will correctly be set to Page1
But if the you go to Page3 from Page2 and then do a browser back then the state.prevUrl will still be Page1 which is false.
Best way I found to deal with this is to add something like this on the gatsby-browser.js
export const onRouteUpdate = ({ location, prevLocation }) => {
if (location && location.state)
location.state.referrer = prevLocation ? prevLocation.pathname : null
}
this way you will have always the previous url available on location.
I resolved my problem with the below piece of code. Here is the ref link https://github.com/gatsbyjs/gatsby/issues/10410
// gatsby-browser.js
exports.onRouteUpdate = () => {
window.locations = window.locations || [document.referrer]
locations.push(window.location.href)
window.previousPath = locations[locations.length - 2]
}
Now you can get previousPath can be accessed from anywhere.

How to display a snackbar conditionally based on redux state using thunks?

I'm writing a website in react which displays information on mobile apps and I'm using redux to store the information about the current app. I have an input text field located in the header where the user can type for some app id and if it's a valid id they will be redirected to another page, if the id is not valid a snackbar will be displayed with appropriate message and if the user just hit enter a snackbar will also be displayed with appropriate message. AppNotFound is the component which wraps snackbar.
I'm using redux thunks to dispatch an action which checks whether the app id is valid (it's an async function) inside onKeyDown method (getAppInfo). Ideally I'd like to get the result from the redux already in onKeyDown method. But because the action is dispatched asynchronically I can't.
So I thought to let render display a snackbar based on the value of found property (whether app was found or not). So at first found would be undefined because the async dispatch wouldn't have returned the result in the render but then found would become true or false and then we can display the snackbar. The render would automatically be called the second time because the props have changed. But this doesn't happen.
What is the correct way in terms of patterns to achieve what I want? I don't want to use componentWillReceiveProps as it's deprecated.
This is my code:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import InputBase from '#material-ui/core/InputBase';
import { withStyles } from '#material-ui/core/styles';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { getAppInfo } from '../../actions/appActions.js';
import constants from '../../constants.js';
import { AppSearchBarInputStyles } from '../styles/Material-UI/muiStyles.js';
import AppNotFound from './AppNotFound.js';
import * as log from 'loglevel';
log.setLevel("debug")
class AppSearchBarInput extends Component {
state = {
appId: '',
snackBarOpen: false
}
onChange = e => {
this.setState({ appId: e.target.value });
}
onKeyDown = e => {
const { appId } = this.state;
const { found } = this.props.app;
if (e.keyCode === constants.ENTER_KEY) {
this.props.getAppInfo({ appId });
if (found) {
this.props.history.push('/moreInfo');
} else {
this.setState({
snackBarOpen: true
});
}
this.setState({
appId: ''
});
}
}
handleCloseSnackBar = () => {
this.setState({
snackBarOpen: false
});
}
render() {
const { classes, app } = this.props;
const { snackBarOpen } = this.state;
const { found, appId } = app;
let message = '';
if (!found) {
message = appId === '' ? constants.MESSAGES.APP_BLANK() : constants.MESSAGES.APP_NOT_FOUND(appId);
}
let displayWhenFoundIsUndefined = null;
if (found === undefined) {
displayWhenFoundIsUndefined = <div>Loading...</div>;
} else {
displayWhenFoundIsUndefined = <AppNotFound message={message}
open={!found}
onClose={this.handleCloseSnackBar}/>;
}
return (
<div>
<InputBase
placeholder="Search…"
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
value={this.state.appId} />
{displayWhenFoundIsUndefined}
</div>
)
}
}
AppSearchBarInput.propTypes = {
classes: PropTypes.object.isRequired
}
const mapStateToProps = state => ({
app: state.app.app
});
const AppSearchBarWithStyles = withStyles(AppSearchBarInputStyles)(AppSearchBarInput);
const AppSearchBarWithStylesConnected = connect(mapStateToProps, { getAppInfo })(AppSearchBarWithStyles);
export default withRouter(AppSearchBarWithStylesConnected);
Since no one still didn't answer this question, I will offer the solution which I recently arrived to.
The problem essentially is that the display of AppSearchBarInput depends mainly on whether the app was found or not. This action must be asynchronic because the information is from Web API. Therefore, I was using redux-thunks and was receiving mobile app information in props. However the snackbarOpen property was in the state which is a problem because the snackbar depends on state property which in itself depends on props which are received asynchronically.
The solution to the predicament is to move snackbarOpen to props as well. So now an action to set snackbarOpen to true should be dispatched directly from getAppInfo thunk if the app was not found, as well as from onKeyDown when the app is blank. On the other hand an action to set snackbarOpen to false should be dispatched from handleCloseSnackBar.

Chain connect/mapStateToProps/mapDispatchToProps functions for code reuse in react-redux

Say I have two redux connected components. The first is a simple todo loading/display container, with the following functions passed to connect(); mapStateToProps reads the todos from the redux state, and mapDispatchToProps is used to request the state to be provided the latest list of todos from the server:
TodoWidgetContainer.js
import TodoWidgetDisplayComponent from '...'
function mapStateToProps(state) {
return {
todos: todoSelectors.getTodos(state)
};
}
function mapDispatchToProps(dispatch) {
return {
refreshTodos: () => dispatch(todoActions.refreshTodos())
};
}
connect(mapStateToProps, mapDispatchTo)(TodoWidgetDisplayComponent);
The second redux component is intended to be applied to any component on a page so that component can indicate whether a global "loading" icon is displayed. Since this can be used anywhere, I created a helper function that wraps MapDispatchToProps in a closure and generates an ID for each component, which is used to make sure all components that requested the loader indicate that they don't need it anymore, and the global loader can be hidden.
The functions are basically as follows, with mapStateToProps exposing the loader visibility to the components, and mapDispatchToProps allowing them to request the loader to show or hide.
Loadify.js
function mapStateToProps(state) {
return {
openLoader: loaderSelectors.getLoaderState(state)
};
}
function mapDispatchToProps() {
const uniqId = v4();
return function(dispatch) {
return {
showLoader: () => {
dispatch(loaderActions.showLoader(uniqId));
},
hideLoader: () => {
dispatch(loaderActions.hideLoader(uniqId));
}
};
};
}
export default function Loadify(component) {
return connect(mapStateToProps, mapDispatchToProps())(component);
}
So now, if I have a component that I want to give access to the loader, I can just do something like this:
import Loadify from '...'
class DisplayComponent = new React.Component { ... }
export default Loadify(DisplayComponent);
And it should give it a unique ID, allow it to request the loader to show/hide, and as long as there is one component that is requesting it to show, the loader icon will show. So far, this all appears to be working fine.
My question is, if I would like to apply this to the todos component, so that that component can request/receive its todos while also being allowed to request the loader to show while it is processing, could I just do something like:
TodoWidgetContainer.js
import Loadify from '...'
import TodoWidgetDisplayComponent from '...'
function mapStateToProps(state) {
return {
todos: todoSelectors.getTodos(state)
};
}
function mapDispatchToProps(dispatch) {
return {
refreshTodos: () => dispatch(todoActions.refreshTodos())
};
}
const TodoContainer = connect(mapStateToProps, mapDispatchTo)(TodoWidgetDisplayComponent);
export default Loadify(TodoContainer);
And will redux automatically merge the objects together to make them compatible, assuming there are no duplicate keys? Or will it take only the most recent set of mapStateToProps/mapDispatchTo unless I do some sort of manual merging? Or is there a better way to get this kind of re-usability that I'm not seeing? I'd really rather avoid having to create a custom set of containers for every component we need.
connect will automatically merge together the combination of "props passed to the wrapper component", "props from this component's mapState", and "props from this component's mapDispatch". The default implementation of that logic is simply:
export function defaultMergeProps(stateProps, dispatchProps, ownProps) {
return { ...ownProps, ...stateProps, ...dispatchProps }
}
So, if you stack multiple levels of connect around each other , the wrapped component will receive all of those props as long as they don't have the same name. If any of those props do have the same name, then only one of them would show up, based on this logic.
Alright, here is what I would do. Create a higher order component (HOC) that adds a new spinner reference to your reducer. The HOC will initialize and destroy references to the spinner in redux by tying into the life cycle methods. The HOC will provide two properties to the base component. The first is isLoading which is a function that takes a boolean parameter; true is on, false is off. The second property is spinnerState that is a readonly boolean of the current state of the spinner.
I created this example without the action creators or reducers, let me know if you need an example of them.
loadify.jsx
/*---------- Vendor Imports ----------*/
import React from 'react';
import { connect } from 'react-redux';
import v4 from 'uuid/v4';
/*---------- Action Creators ----------*/
import {
initNewSpinner,
unloadSpinner,
toggleSpinnerState,
} from '#/wherever/your/actions/are'
const loadify = (Component) => {
class Loadify extends React.Component {
constructor(props) {
super(props);
this.uniqueId = v4();
props.initNewSpinner(this.uniqueId);;
this.isLoading = this.isLoading.bind(this);
}
componentWillMount() {
this.props.unloadSpinner(this.uniqueId);
}
// true is loading, false is not loading
isLoading(isOnBoolean) {
this.props.toggleSpinner(this.uniqueId, isOnBoolean);
}
render() {
// spinners is an object with the uuid as it's key
// the value to the key is weather or not the spinner is on.
const { spinners } = this.props;
const spinnerState = spinners[this.uniqueId];
return (
<Component isLoading={this.isLoading} spinnerState={spinnerState} />
);
}
}
const mapStateTopProps = state => ({
spinners: state.ui.spinners,
});
const mapDispatchToProps = dispatch => ({
initNewSpinner: uuid => dispatch(initNewSpinner(uuid)),
unloadSpinner: uuid => dispatch(unloadSpinner(uuid)),
toggleSpinner: (uuid, isOn) => dispatch(toggleSpinnerState(uuid, isOn))
})
return connect(mapStateTopProps, mapDispatchToProps)(Loadify);
};
export default loadify;
Use Case Example
import loadify from '#/location/loadify';
import Spinner from '#/location/SpinnerComponent';
class Todo extends Component {
componentWillMount() {
this.props.isLoading(true);
asyncCall.then(response => {
// process response
this.props.isLoading(false);
})
}
render() {
const { spinnerState } = this.props;
return (
<div>
<h1>Spinner Testing Component</h1>
{ spinnerState && <Spinner /> }
</div>
);
}
}
// Use whatever state you need
const mapStateToProps = state => ({
whatever: state.whatever.youneed,
});
// use whatever dispatch you need
const mapDispatchToProps = dispatch => ({
doAthing: () => dispatch(doAthing()),
});
// Export enhanced Todo Component
export default loadify(connect(mapStateToProps, mapDispatchToProps)(Todo));

Categories

Resources