How to import FooterCaption from 'react-images'? - reactjs

I am trying to use the library 'react-images' in my reactjs project. I am receiving the error "Unexpected token" in the react-images\src\components\Footer.js file. Also, on the same line i have the error "'import ... =' can only be used in a .ts file.".
import type { PropsWithStyles, ViewType } from '../types';
Also, I am receiving the error "'type aliases' can only be used in a .ts file." in many of the component files in 'react-images' library. Why is this? Thanks.
import React, { Component, Fragment } from 'react';
import Carousel, { Modal, ModalGateway, FooterCaption } from 'react-images';

You misunderstand how this library is designed. If you look at the documentation, FooterCaption is listed under Component API. That means FooterCaption is part of the API for the Carousel component meaning that this is designed with the Slots Pattern.
If you look at the example code above it, it shows you how this works.
<Carousel components={{ Header: CustomHeader }} />
The Carousel component has a prop called components which takes an object. This object is expected to have keys that are one of the various replaceable components listed under Component API. The value is expected to be a something that React can render; typically a component. This example is replacing the Header with a custom header component called CustomHeader.
If you don't override the component, then Carousel will render something by default as described in the documentation for each component under Component API.
If you would like to override the default FooterCaption, then you will do something like this:
<Carousel components={{ FooterCaption: MyCustomFooterCaption }} />
Where MyCustomFooterCaption is a component you've defined elsewhere. The props it will receive from the Carousel component can be found in the source code.
To summarize:
You don't need to import FooterCaption.
If you plan on overriding the default FooterCaption, then create your own component and pass it in as shown in example.
The same goes for everything listed under Component API.

Related

How to inject style into Modal component?

I'm building a React app using Dart SASS. Things are generally going well and I particularly appreciate how the styles for each component are isolated to that component - ie. ComponentName.module.scss
But I've just built a new Modal component that is merely a wrapper for the popular react-modal component installable via npm.
What I'd ideally like to be able to do is pass in a className string that is merely a reference to an SCSS class in my parent component and have it override the default styles in Modal.jsx.
Example: I have a component called SignIn.jsx. It has a Forgot Password link that, when clicked, displays a modal to allow the user to enter their email address. What would be ideal is to be able to define an SCSS class in SignIn.module.scss and then pass into Modal.jsx this class when I call <Modal className={...myCustomClass} ... />
I actually have been able to accomplish this with a global SCSS class definition but haven't been able to figure out how to do so as I described above.
Is what I'm seeking to do possible? Are there any articles on how to do this?
While I appreciate #iamhuynq trying to help, there's much more that can be said, which will hopefully help others in the future.
To summarize the issue, imagine you're using TypeScript with React and have a parent component with a companion SCSS file:
ParentComponent.tsx
ParentComponent.module.scss
In this parent component you want to utilize a child component consisting of these files:
ChildComponent.tsx
ChildComponent.module.scss
You want the ability to inject a custom style into the ChildComponent. More precisely, you have an SCSS class defined in ParentComponent.module.scss that you want to be utilized by ChildComponent.tsx. To accomplish this, do the following in the child component:
import * as React from 'react';
import cx from 'classnames';
import styles from './ChildComponent.module.scss';
interface IChildComponent {
className?: any; // Note: I tried more specific types but none of them worked
children: React.ReactNode;
}
const ChildComponent = ({ className, children }: IChildComponent) => {
return (
// Your version of this content will necessarily be different
<div className={cx(styles.childComponentMain, className)}>
// More content here
</div>
);
};
export default ChildComponent;
With this approach I am able to inject a style defined in ParentComponent.module.scss into ChildComponent.tsx and have it amend to those styles already defined in ChildComponent.module.scss.

react-intl v4 upgrade `IntlProvider` not found preventing component from displaying when using `injectIntl` wrapper

I am trying to upgrade from react-intl v 2.3.0 to 4.5.1. I have run into a few issues around the injectIntl HOC since the upgrade. I have a shared component library within a monorepo that is imported into different features (combination of imported shared and local unique components in a separate part of the repo). However, my IntlProvider lives in my shared components library and we import a component called AppShell that includes any needed providers (including intl) that wraps the top level of every feature.
I followed advice found on an issue on the formatjs repo and deleted the react-intl version from my shared component library. This solved most of my issues with a few caveats.
Note, all examples below are using a feature folder with react-intl version 4.5.1, and a shared component library having no version of react-intl installed
Fix attempt 1
If I try to use the injectIntl HOC from react-intl the component will not render on the page and I get the following errors:
code example (AppShell wrapper component lives in the top level ReactDOM.render function):
import { FormattedMessage, injectIntl } from 'react-intl';
// shared component library
import { Alert } from '#shared/components/alert';
// component custom to feature, also can contain shared components
import WorkspaceListContainer from './workspaceListContainer';
import messages from './messages';
export class AppLifecycleMenu extends Component {
render() {
const deleteAlertTitle = this.props.intl.formatMessage(
messages.deleteAlertTitle,
{ alertName: name }
);
return (
<Fragment>
<WorkspaceListContainer />
<Alert
title={deleteAlertTitle}
okButtonText={<FormattedMessage {...messages.deleteOkButton} />}
cancelButtonText={<FormattedMessage {...messages.deleteCancelButton} />}
/>
</Fragment>
);
}
}
export default injectIntl(AppLifecycleMenu);
Note, in a lot of our shared components, intl messages can be passed in as props and some components are wrapped in their own injectIntl HOC to intl default versions of props (like a default button label).
Fix attempt 2
However, if I import an injectIntl helper we have in our shared resource library, the component renders but still displays an error message:
injectIntlHelper code:
// only apply intl in non-test environments
export default Component => process.env.NODE_ENV === TEST_ENV ? Component : injectIntl(Component);
code example (AppShell wrapper component lives in the top level ReactDOM.render function):
import { FormattedMessage, injectIntl } from 'react-intl';
// shared component library
import { Alert } from '#shared/components/alert';
import injectIntl from '#shared/utilities/injectIntl';
// component custom to feature, also can contain shared components
import WorkspaceListContainer from './workspaceListContainer';
import messages from './messages';
export class DeleteWorkspaceAlert extends Component {
render() {
const deleteAlertTitle = this.props.intl.formatMessage(
messages.deleteAlertTitle,
{ alertName: name }
);
return (
<Fragment>
<WorkspaceListContainer />
<Alert
title={deleteAlertTitle}
okButtonText={<FormattedMessage {...messages.deleteOkButton} />}
cancelButtonText={<FormattedMessage {...messages.deleteCancelButton} />}
/>
</Fragment>
);
}
}
export default injectIntl(AppLifecycleMenu);
component tree with intlprovider:
Error message:
Fix attempt 3
I also tried only having react-intl installed in the shared resource library but that results in this error message:
Environment
I have tried going down versions in react-intl, but this issue persists back down into the 3.0 and up versions
I've been trying different combinations and looking online for a few days, are there any other changes I can make to get rid of these errors? Is anything jumping out as something I am missing adding or updating between versions?
For anyone who comes across this, my issue was solved by following/modifying the fix from the issue: https://github.com/formatjs/formatjs/issues/1620
Unlike the issue linked above, my projects IntlProvider lives in the shared resource library and is exported to wrap components. Therefore I deleted the react-intl dependency from all folders other than my shared resource library and exported any needed components from there.
So my imports in my non-shared components folder would look like
import injectIntl, { FormattedMessage, FormattedDate } from '#shared/utils/intl';
with component(s) in my shared library that have files that look like this
import { FormattedMessage } from 'react-intl;
export FormattedMessage;
Relevant quote from the issue:
I think the reason [having multiple dependencies] worked with older version is old React context API. New React context API rely on same reference. You project instantiates react context from different node_modules thus contexts are not same reference. This also means you are bundling react-intl twice in your application.

Can we have React 16 Portal functionality React Native?

I'm using React Native which ships with React 16 alpha release which supports portals. While in browser and having access to DOM we can use id or classes to access element from anywhere in component/file hierarchy like this:
const modalRoot = document.getElementById('modal-root');
and pass it to createPortal(child, container) container arg. React docs clearly says than container should be DOM element:
The second argument (container) is a DOM element.
This function is also a method of ReactDOM which doesn't exist in React Native.
Is there a way to achieve the similar functionality in React Native?
Use case:
I want to render an animated overlay in the root of my application but pass the Animated values props to it from a parent deep in the tree hierarchy (can't use Redux actions for such things).
I had similar problem where I wanted to render overlay on top of everything from deeply nested child component. I solved my problem with React Native's Modal
It renders its content on top of everything :) Easy to use and no need for extra dependencies
I don't think react-native provides this functionality in its own API.
But there is a library available which provides the similar functionality. react-gateway
As per the docs of react-gateway,
It also works in universal (isomorphic) React applications without any additional setup and in React Native applications.
React Gateway does not directly depend on react-dom, so it works fine with React Native under one condition:
You must pass React Native component like View or similar to component prop of .
import React from 'react';
import { Text, View } from 'react-native';
import {
Gateway,
GatewayDest,
GatewayProvider
} from 'react-gateway';
export default class Application extends React.Component {
render() {
return (
<GatewayProvider>
<View>
<Text>React Gateway Native Example</Text>
<View>
<Gateway into="one">
<Text>Text rendered elsewhere</Text>
</Gateway>
</View>
<GatewayDest name="one" component={View} />
</View>
</GatewayProvider>
);
}
}
The above example is taken from the repo itself. react native example
One way to render the items above the screen can be done using react-native-paper library.
import * as React from 'react';
import { Text } from 'react-native';
import { Portal } from 'react-native-paper';
const MyComponent = () => (
<Portal.Host>
<Text>Content of the app</Text>
</Portal.Host>
);
export default MyComponent;
Portal host renders all of its children Portal elements. For example, you can wrap a screen in Portal.Host to render items above the screen.
Here is the link which describes its usage:
https://callstack.github.io/react-native-paper/portal-host.html

this.props.history.push not working

When i export a component like:
export default class Link extends React.Component{
onLogout() {
this.props.history.push('/');
}
the button that this is tied to correctly changes the page in react-router v4.
However, in my main.js file, I am currently trying to get something like:
if (insert conditional here) {
this.props.history.push('/');
}
to work. But it just give me a type error.
'Uncaught TypeError: Cannot read property 'history' of undefined'.
I do have all the correct dependencies installed, and it works just fine in my other component. I'm currently having this if statement in the main js file (its a small project im practicing to understand v4), so I'm thinking it might be because I'm not extending a class.
Does anyone have any idea why the same code wouldn't be working in the main file, and is there a workaround for this? All the react-router v4 changes are befuddling this rookie.
This means that this.props is not defined, because you are using this.props in a callback where this is not what you think it is. To solve this, use your callback like this:
<button onClick={this.onLogout.bind(this)}>
instead of
<button onClick={this.onLogout}>
You can also do
import { browserHistory } from 'react-router'
... browserHistory.push('/');
Edit: Regarding the latter, you can also wrap your component with this:
import { withRouter } from 'react-router';
// in YourComponent:
... this.props.router.push('/');
export default withRouter(YourComponent);
It may be better than browserHistory because you don't have to specify the history type (could be changed to hashHistory and still work).
I would suggest you to not a address directly into the history but use .
You can send the user to the page and you can conditionally check if he is allowed to see the content if yes then render in render method return the component else return
This would result in a cleaner code.
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Redirect.md

Please explain this abbreviated ES6 JSX declaration

An example in the SurviveJS handbook in the chapter on React and Webpack has me confused.
In Note.jsx:
import React from 'react';
export default () => <div>Learn Webpack</div>;
This deviates in a number of ways from what appears to be the standard way of declaring React components using JSX:
import React from 'react';
class Note extends React.Component {
render() {
return <div>Learn Webpack</div>;
}
}
How does the first example work?
How does it know the component is called Note so that it can be referred to as <Note/> in some parent component? Simply by filename match (removing the .jsx part?)
Where's the render() function? And how is it possible to omit it?
What are the limitations of this approach? I am guessing that it only works for wrapping a very simple rendered output, just mapping properties into some HTML...
Where is this style documented? I can't seem to find any official documentation
It doesn't, when you do <Note /> that is just looking for a variable named Note in the local scope. When the component is imported into another file, you can name it whatever you want. e.g. import Note from './Note'; would import the default-exported function in your example.
This is a stateless function component, https://facebook.github.io/react/docs/reusable-components.html#stateless-functions, as you linked to yourself. The function itself is the render, it has no class instance.
They can store no state since they just take inputs and render outputs.
Your specific example is just an arrow function. The documentation linked above uses standard non-arrow functions, but they are essentially interchangable in this case. e.g.
export default () => <div>Learn Webpack</div>;
is the same as
export default function(){
return <div>Learn Webpack</div>;
}

Resources