Flow type system in React components - javascript

i start to use Flow in my React application and i have question about the type system.
I have a stateless component like this
export type LinkProps = {
to: string,
icon: React$Element<any>,
style: Object
}
const Link = ({
to,
icon,
style
}: LinkProps) => (
<sample>
</sample>
)
And another component where override some props
const NavLink = (props: LinkProps) => <Link icon={<Icon />} {...props} />
So, if i use the Link component directly i have the Flow type system but is not the case with the NavLink component.
Why i can use the NavLink component without respect the type system?

It sounds like you might need to add // #flow to the top of the file where you are using the NavLink component

Related

React and typescript ReactRouterProps issue

I need to deconstruct my general props and match (to get an "id" from the URL).
Component (using props):
interface Props extends RouteComponentProps<{id: string}>{
initialProjectName: string;
workspaceId: string;
}
const AddResources: React.FC<Props> = ({
initialProjectName,
workspaceId,
match,
}) => {
const projectId = match.params.id; // used here without any error
But the parent component is showing error when I pass props
Parent
<div>
<h1>Start Project Page</h1>
<AddResources
initialProjectName={initialProjectName}
workspaceId={workspaceId} // error
/>
</div>
Error Message
By using RouteComponentProps you specify that your component requires the route props, but you will also need to make sure you pass these props. If the component is directly underneath a Route (i.e. as a child or by using <Route component={..}/>, the route props are passed automatically, if not, you can use withRouter (docs) to obtain them:
const AddResourcesWithRouter = withRouter(AddResources);
and use AddResourcesWithRouter istead of AddResources.
I think you should try useHistory, useRouteMatch, useLocation or wrap withRouter(AddResources)

React (native) - inject custom components instead standard ones in 3rd party code/components

For example i have library/package which exports some component:
function SomeComponent() {
...
return (
<View>
...
<TextInput ... />
...
</View>
);
}
Is there any way I can use SomeComponent but instead of TextInput I somehow inject my custom MyCustomTextInput?
I know that is possible to create SomeComponent with CustomTextInput prop (it does not matter if CustomTextInput default value is specified like this or with defaultProps static initialization):
function SomeComponent({ CustomTextInput = TextInput }) {
...
return (
<View>
...
<CustomTextInput ... />
...
</View>
);
}
What I need is easy way to tell to the whole application (all packages, all our modules/code) "where ever you see TextInput component use my custom MyCustomTextInputComponent". Is this possible in react/react-native?
You can make index for component export package with conditions:
Look at example project:
Example: https://snack.expo.io/#djalik/thrilled-donut
index.js:
import React from 'react';
import {TextInput} from 'react-native';
const MyTextInput=()=>{
return <TextInput value={'custom'}/>
}
const MyTextInput2=()=>{
return <TextInput value={'custom2'}/>
}
let custom1 = false;
export default (custom1?MyTextInput:MyTextInput2);
and import in app where you need it:
import {MyTextInput} from './components'
What you want to achieve (substitute react-native's TextInput with your own component across the entire app) is not possible to do. You can't force library to render another component either (unless it specifically lets you pass that component as a prop). Solution here would be forking this library on github, making necessary changes to support custom component prop and using github link in your package.json file

Converting functional component to class based component

I need to convert a functional component to a class based component. I am fairly new to React but I have tried to convert the component. I get the error - ReferenceError: Cant find variable: Props
My question is, where do I add props which was present in the class based component to make the conversion work ?
The class based component which is a modal with a form triggered from a parent component,this works well. The form uses state variables which dont work in a class based component so I need to convert the current functional component to a class based component. I'm using version 16.6.3 of React because other packages do not work with newer versions of React-Native so I cant use hooks with this version.
Functional component
const ShowModal = props => (
<Modal
visible={props.display}
animationType="slide"
onRequestClose={() => console.log("closed")}
>
...Other stuff in here.
</Modal>
);
export default ShowModal;
Class based component
export default class ShowModal extends Component {
state = {
};
render() {
return (
...Other stuff in here
);
}
}
I get the error - ReferenceError: Cant find variable: Props
In class based components props is exposed in the main scope of the class. You should read it using this keyword
class Component extends React.Component{
render(){return this.props.value}
}
I presume you want to use State, as the reason for moving to a Class component. Instead I suggest to use React Hooks which is the newest and elegant approach.
const ShowModal = props => (
const [state, setState] = React.useState({});
<Modal
visible={props.display}
animationType="slide"
onRequestClose={() => console.log("closed")}
>
...Other stuff in here.
</Modal>
);
React Hooks: https://medium.com/frontmen/react-hooks-why-and-how-e4d2a5f0347

Get an active route with react-router in ReactJs

I am creating a project using reactjs.In my application i am getting the active route using this:
this.context.router.isActive
but getting undefined, i am using the react-router 4.Earlier this was worked for me when am using the lower version of react-router.
Here is my code:
class NavLink extends React.Component {
render() {
console.log( this.context.router.isActive)
let isActive = this.context.router.isActive(this.props.to, true);
let className = isActive ? "active" : "";
return(
<li className={className} {...this.props}>
<Link {...this.props}/>
</li >
);
}
}
NavLink.contextTypes = {
router: PropTypes.object
};
The architecture has changed in react-router v4 and this.context.router.isActive is no longer supported.
In react-router-v4, you could instead of creating a NavLink yourself use the exposed NavLink component.
From the documentation:
NavLink
A special version of the that will add styling attributes to
the rendered element when it matches the current URL.
import { NavLink } from 'react-router-dom'
<NavLink to="/about">About</NavLink>
It also provides you an activeClassName prop:
activeClassName: string
The class to give the element when it is active. The default given
class is active. This will be joined with the className prop.
<NavLink
to="/faq"
activeClassName="selected"
>FAQs</NavLink>
Why is this.context.router.isActive not supported:
Here is an excerpt from a github issue
Rendering a <Route> does not necessarily mean "only render when you match the current location". For example, it can be used inject the router variables from the context into a component as props.
In <NavLink>, the <Route> is using the children prop, which means that it will call the children function whether or not the route matches. If the match is null, then we know that it did not match.
If you would prefer not to use <Route children> in this way, React Router offers an imperative approach with the matchPath function. This is what <Switch>es and <Route>s use internally to match a location against a path.
If your component is not receiving the Router props, then you could inject it using the withRouter HOC
import { withRouter } from 'react-router';
export class withRouter(MyComponent);
A simple way to style active router
import NavLink
import { NavLink } from 'react-router-dom';
<NavLink className={({ isActive }) => (isActive ? 'active-link' : 'link')} to="/home">Home</NavLink>
in style.css
.active-link {
color: hsl(96, 82%, 35%);
}
customize the style looks more beautiful.
~cheers

Set required props on component

Say that I create a custom component like this:
const MyComponent = (props) => (
<div
className={props.name}
id={props.id}>
{props.children}
</div>
)
And I need to make sure that props contain the variables name and id, because otherwise what I want to do is not going to work (now I know that this code will work anyhow, but hypothetically say that it won't).
Is there a way in React to demand that certain props are passed to a component?
Maybe this is something that is obvious, but I couldn't find any information about it.
You can use PropTypes. It was earlier a part of React but now it has its own npm package, https://www.npmjs.com/package/prop-types. This will give you a runtime error if ther props are not provided. Its also useful, because linters can warn you if you miss them.
https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prop-types.md
import React from 'react';
import PropTypes from 'prop-types';
const MyComponent = (props) => (
<div
className={props.name}
id={props.id}>
{props.children}
/>
);
MyComponent.propTypes = {
name: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
element: PropTypes.arrayOf(PropTypes.element).isRequired
};

Categories