React pre-processing props - reactjs

I'd to know if there's any component or helper function to pre-process/transform properties before delivering to the component itself.
I've using the redux's connect function to achieve this behaviour but for components that doesn`t connect to the redux store doesn't make much sense. The following illustrates the ideal solution:
const MyComponent = (props) => { ... }
const propsProcessor = (props) => {
//do something here and return the processed props
}
export default processingProps(propsProcessor)(MyComponent);
This way I could pass an array to the component, group into an json and use it inside the component.

Related

How to pass props from parent to grandchild component in react

I have tried pass value from parent to grandchild component, and it works. While I am thinking if there is another simpler or other way of passing props in shorter path.
What I did is quite cumbersome in codesandbox
There may be a common problem in react world called prop drilling by passing data to children only using props.
I would recommend only 2-level passing, if you need pass data deeper then you probably doing something wrong.
Use one of popular state management library (if your project is big) or React context (which is awesome)
Create a folder called /contexts and put contexts there. The structure of files can be like shown below:
First you need to create a context itself
type ClientContextState = {
data: User;
set: (data: User) => void;
logout: () => void;
};
// empty object as a default value
export const UserContext = createContext<UserContextState>({} as UserContextState);
Then create a Provider wrapper component
export const UserProvider = ({ children }: Props) => {
const [data, setData] = useState<User>({});
const sharedState = {
data,
set: setData
logout: () => setData(null)
}
return <UserContext.Provider value={sharedState}>{children}</UserContext.Provider>
});
You may also want to have an alias of useContext hook:
export const useUser = () => {
return useContext(UserContext);
};
After all this whenever you wrap your components or app to <UserProvider>...</UserProvider> you can use our hook to access data and methods form sharedState from any place you want:
export LogoutButton = () => {
const {data, logout} = useUser();
return <Button onClick={() => logout()}>Logout from {data.name}</Button>
}
Whenever you want to pass props or data from Grandparent to child component, always use react-redux. This is useful to maintain the state and access the data from anywhere/any component.
Another way is to use useContext hooks which you can use to pass the props
Following are the steps to use useContext hooks
Creating the context
The built-in factory function createContext(default) creates a context instance:
import { createContext } from 'react';
const Context = createContext('Default Value');
The factory function accepts one optional argument: the default value.
Providing the context
Context.Provider component available on the context instance is used to provide the context to its child components, no matter how deep they are.
To set the value of context use the value prop available on the
<Context.Provider value={value} />:
function Main() {
const value = 'My Context Value';
return (
<Context.Provider value={value}>
<MyComponent />
</Context.Provider>
);
}
Again, what’s important here is that all the components that’d like later to consume the context have to be wrapped inside the provider component.
If you want to change the context value, simply update the value prop.
Consuming the context: Consuming the context can be performed in 2 ways.
The first way, the one I recommend, is to use the useContext(Context) React hook:
import { useContext } from 'react';
function MyComponent() {
const value = useContext(Context);
return <span>{value}</span>;
}
Generally it's helpful to consider whether moving state down the hierarchy would be the simplest route. That means lifting the component instantiation to a place closer to the state being used. In your example, that could mean Component_data is used inside Component and passed to its children there, removing one step in the nested data flow. Even better, would be that Child.a accesses Component_data.A directly.
In a real app with cases where accessing the data directly is less feasible, a solution I lean towards is using Context to set data in the parent that retrieves it, and then I can access it however deeply nested the component might be that needs it.
i.e. in App I would create the Context provider, and in ChildA I access it via useContext hook.
Further reading
https://reactjs.org/docs/context.html
https://overreacted.io/before-you-memo/#solution-1-move-state-down (this post is about an alternative to using useMemo but has an illustrative example of why moving state down is a good thing)

const in class react i18n [duplicate]

In this example, I have this react class:
class MyDiv extends React.component
constructor(){
this.state={sampleState:'hello world'}
}
render(){
return <div>{this.state.sampleState}
}
}
The question is if I can add React hooks to this. I understand that React-Hooks is alternative to React Class style. But if I wish to slowly migrate into React hooks, can I add useful hooks into Classes?
High order components are how we have been doing this type of thing until hooks came along. You can write a simple high order component wrapper for your hook.
function withMyHook(Component) {
return function WrappedComponent(props) {
const myHookValue = useMyHook();
return <Component {...props} myHookValue={myHookValue} />;
}
}
While this isn't truly using a hook directly from a class component, this will at least allow you to use the logic of your hook from a class component, without refactoring.
class MyComponent extends React.Component {
render(){
const myHookValue = this.props.myHookValue;
return <div>{myHookValue}</div>;
}
}
export default withMyHook(MyComponent);
Class components don't support hooks -
According to the Hooks-FAQ:
You can’t use Hooks inside of a class component, but you can definitely mix classes and function components with Hooks in a single tree. Whether a component is a class or a function that uses Hooks is an implementation detail of that component. In the longer term, we expect Hooks to be the primary way people write React components.
As other answers already explain, hooks API was designed to provide function components with functionality that currently is available only in class components. Hooks aren't supposed to used in class components.
Class components can be written to make easier a migration to function components.
With a single state:
class MyDiv extends Component {
state = {sampleState: 'hello world'};
render(){
const { state } = this;
const setState = state => this.setState(state);
return <div onClick={() => setState({sampleState: 1})}>{state.sampleState}</div>;
}
}
is converted to
const MyDiv = () => {
const [state, setState] = useState({sampleState: 'hello world'});
return <div onClick={() => setState({sampleState: 1})}>{state.sampleState}</div>;
}
Notice that useState state setter doesn't merge state properties automatically, this should be covered with setState(prevState => ({ ...prevState, foo: 1 }));
With multiple states:
class MyDiv extends Component {
state = {sampleState: 'hello world'};
render(){
const { sampleState } = this.state;
const setSampleState = sampleState => this.setState({ sampleState });
return <div onClick={() => setSampleState(1)}>{sampleState}</div>;
}
}
is converted to
const MyDiv = () => {
const [sampleState, setSampleState] = useState('hello world');
return <div onClick={() => setSampleState(1)}>{sampleState}</div>;
}
Complementing Joel Cox's good answer
Render Props also enable the usage of Hooks inside class components, if more flexibility is needed:
class MyDiv extends React.Component {
render() {
return (
<HookWrapper
// pass state/props from inside of MyDiv to Hook
someProp={42}
// process Hook return value
render={hookValue => <div>Hello World! {hookValue}</div>}
/>
);
}
}
function HookWrapper({ someProp, render }) {
const hookValue = useCustomHook(someProp);
return render(hookValue);
}
For side effect Hooks without return value:
function HookWrapper({ someProp }) {
useCustomHook(someProp);
return null;
}
// ... usage
<HookWrapper someProp={42} />
Source: React Training
you can achieve this by generic High order components
HOC
import React from 'react';
const withHook = (Component, useHook, hookName = 'hookvalue') => {
return function WrappedComponent(props) {
const hookValue = useHook();
return <Component {...props} {...{[hookName]: hookValue}} />;
};
};
export default withHook;
Usage
class MyComponent extends React.Component {
render(){
const myUseHookValue = this.props.myUseHookValue;
return <div>{myUseHookValue}</div>;
}
}
export default withHook(MyComponent, useHook, 'myUseHookValue');
Hooks are not meant to be used for classes but rather functions. If you wish to use hooks, you can start by writing new code as functional components with hooks
According to React FAQs
You can’t use Hooks inside of a class component, but you can
definitely mix classes and function components with Hooks in a single
tree. Whether a component is a class or a function that uses Hooks is
an implementation detail of that component. In the longer term, we
expect Hooks to be the primary way people write React components.
const MyDiv = () => {
const [sampleState, setState] = useState('hello world');
render(){
return <div>{sampleState}</div>
}
}
You can use the react-universal-hooks library. It lets you use the "useXXX" functions within the render function of class-components.
It's worked great for me so far. The only issue is that since it doesn't use the official hooks, the values don't show react-devtools.
To get around this, I created an equivalent by wrapping the hooks, and having them store their data (using object-mutation to prevent re-renders) on component.state.hookValues. (you can access the component by auto-wrapping the component render functions, to run set currentCompBeingRendered = this)
For more info on this issue (and details on the workaround), see here: https://github.com/salvoravida/react-universal-hooks/issues/7
Stateful components or containers or class-based components ever support the functions of React Hooks, so we don't need to React Hooks in Stateful components just in stateless components.
Some additional informations
What are React Hooks?
So what are hooks? Well hooks are a new way or offer us a new way of writing our components.
Thus far, of course we have functional and class-based components, right? Functional components receive props and you return some JSX code that should be rendered to the screen.
They are great for presentation, so for rendering the UI part, not so much about the business logic and they are typically focused on one or a few purposes per component.
Class-based components on the other hand also will receive props but they also have this internal state. Therefore class-based components are the components which actually hold the majority of our business logic, so with business logic, I mean things like we make an HTTP request and we need to handle the response and to change the internal state of the app or maybe even without HTTP. A user fills out the form and we want to show this somewhere on the screen, we need state for this, we need class-based components for this and therefore we also typically use class based components to orchestrate our other components and pass our state down as props to functional components for example.
Now one problem we have with this separation, with all the benefits it adds but one problem we have is that converting from one component form to the other is annoying. It's not really difficult but it is annoying.
If you ever found yourself in a situation where you needed to convert a functional component into a class-based one, it's a lot of typing and a lot of typing of always the same things, so it's annoying.
A bigger problem in quotation marks is that lifecycle hooks can be hard to use right.
Obviously, it's not hard to add componentDidMount and execute some code in there but knowing which lifecycle hook to use, when and how to use it correctly, that can be challenging especially in more complex applications and anyways, wouldn't it be nice if we had one way of creating components and that super component could then handle both state and side effects like HTTP requests and also render the user interface?
Well, this is exactly what hooks are all about. Hooks give us a new way of creating functional components and that is important.
React Hooks let you use react features and lifecycle without writing a class.
It's like the equivalent version of the class component with much smaller and readable form factor. You should migrate to React hooks because it's fun to write it.
But you can't write react hooks inside a class component, as it's introduced for functional component.
This can be easily converted to :
class MyDiv extends React.component
constructor(){
this.state={sampleState:'hello world'}
}
render(){
return <div>{this.state.sampleState}
}
}
const MyDiv = () => {
const [sampleState, setSampleState] = useState('hello world');
return <div>{sampleState}</div>
}
It won't be possible with your existing class components. You'll have to convert your class component into a functional component and then do something on the lines of -
function MyDiv() {
const [sampleState, setSampleState] = useState('hello world');
return (
<div>{sampleState}</div>
)
}
For me React.createRef() was helpful.
ex.:
constructor(props) {
super(props);
this.myRef = React.createRef();
}
...
<FunctionComponent ref={this.myRef} />
Origin post here.
I've made a library for this. React Hookable Component.
Usage is very simple. Replace extends Component or extends PureComponent with extends HookableComponent or extends HookablePureComponent. You can then use hooks in the render() method.
import { HookableComponent } from 'react-hookable-component';
// πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡
class ComponentThatUsesHook extends HookableComponent<Props, State> {
render() {
// πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡
const value = useSomeHook();
return <span>The value is {value}</span>;
}
}
if you didn't need to change your class component then create another functional component and do hook stuff and import it to class component
Doesn't work anymore in modern React Versions. Took me forever, but finally resulted going back to go ol' callbacks. Only thing that worked for me, all other's threw the know React Hook Call (outside functional component) error.
Non-React or React Context:
class WhateverClass {
private xyzHook: (XyzHookContextI) | undefined
public setHookAccessor (xyzHook: XyzHookContextI): void {
this.xyzHook = xyzHook
}
executeHook (): void {
const hookResult = this.xyzHook?.specificHookFunction()
...
}
}
export const Whatever = new WhateverClass() // singleton
Your hook (or your wrapper for an external Hook)
export interface XyzHookContextI {
specificHookFunction: () => Promise<string>
}
const XyzHookContext = createContext<XyzHookContextI>(undefined as any)
export function useXyzHook (): XyzHookContextI {
return useContext(XyzHookContextI)
}
export function XyzHook (props: PropsWithChildren<{}>): JSX.Element | null {
async function specificHookFunction (): Promise<void> {
...
}
const context: XyzHookContextI = {
specificHookFunction
}
// and here comes the magic in wiring that hook up with the non function component context via callback
Whatever.setHookAccessor(context)
return (
< XyzHookContext.Provider value={context}>
{props.children}
</XyzHookContext.Provider>
)
}
Voila, now you can use ANY react code (via hook) from any other context (class components, vanilla-js, …)!
(…hope I didn't make to many name change mistakes :P)
Yes, but not directly.
Try react-iifc, more details in its readme.
https://github.com/EnixCoda/react-iifc
Try with-component-hooks:
https://github.com/bplok20010/with-component-hooks
import withComponentHooks from 'with-component-hooks';
class MyComponent extends React.Component {
render(){
const props = this.props;
const [counter, set] = React.useState(0);
//TODO...
}
}
export default withComponentHooks(MyComponent)
2.Try react-iifc: https://github.com/EnixCoda/react-iifc

Converting a const function to a component

I'm trying to convert this line of code to a component. This line of code works:
const GlobalCss = withStyles(s)(() => null);
export default GlobalCss;
This is what it looks like as a component:
const GlobalCss = function(props){
return withStyles(props.css)(() => null);
}
But this compiles with the error:
Objects are not valid as a React child
It's probably related with material-ui withStyle HOC's issue
For your code
const App = function(props){
return withStyles()(() => null);
}
Is the same as the below arrow function version
const App = props => withStyles()(() => null); // Nop
And this works
const App = withStyles()(() => null); // OK
So if you need props been defined, use it inside the style related HOC seems fine.
const App = withStyles()(props => null); // OK
In our prod, we use other HOCs like redux connect which is related to props inside withStyles, too.
Sample:
export const ComponentName = withTheme(withStyles(styles)(connect(
(store: Store) => ({...}), // props
(dispatch: any) => ({...}) // props
)(YourComponent)));
You can try it online here
Update
If the demand needs to pass classes done via props
Use withStyles would be good enough
interface Props extends WithStyles<typeof styles> {
classes: any,
...
Update V.2
If you want to use global styles as well as withStyles, there is an option to make a common custom HOC behind the withStyles.
export const YourComponent = withStyles()(
mergeGlobalStylesHOC(() => null)
);
Update V.3
And for functional component, export the global style hooks would be a good practice, also.
And if you want to custom all the material-component without writing the related style everywhere, simply reuse the customized component would be good.
YOU have an issue to use the HOC try to use this shape for a higher-order component in react
I thank you should read about Hoc
with styles is the what you want injection inside the component as GlobalClass
function GlobalClass(props) {
... //the null or as you want what is you return
}
export default withStyles(styles)(GlobalClass);
I think this is the same what you want
(props=>null)// is equal as the function above
I think if used the shape it will be work tell me if it works

How is this dispatch function coming from props?

I'm trying to learn from reading this app's code, and I am confused how you get dispatch from the props in this line of code:
_handleSubmit(e) {
e.preventDefault();
const { email, password } = this.refs;
const { dispatch } = this.props;
dispatch(Actions.signIn(email.value, password.value));
}
https://github.com/bigardone/phoenix-trello/blob/master/web/static/js/views/sessions/new.js#L17
Hoping someone can explain how calling this.props will return a dispatch?
react-redux is a library that helps components get values from the Redux store in a predictable and performant way. The main tool it provides is a function called connect, which wraps Redux components providing them with store values as props. The key part of the code you link to is at the bottom: https://github.com/bigardone/phoenix-trello/blob/master/web/static/js/views/sessions/new.js#L70-L74.
Say you have a value in the Redux store named counter. You want your component CounterDisplay to know about this value, and update when it changes:
class CounterDisplay extends Component {
render () {
const { counter, dispatch } = this.props
return (
<div>{counter}</div>
)
}
}
Those variables are going to be undefined unless you've explicitly put the values into props the 'old fashioned way':
<CounterDisplay counter={1} dispatch={() => {}} />
That's where connect comes in. It knows about the Redux store (often using another component called Provider) and can place values from it into the props of the component it's wrapping. It returns what's called a Higher Order Component (HOC): one that wraps another to perform a specific function, in this case connection to the store.
Here's how we'd get the counter value into props:
function mapStateToProps (state) {
// Slightly confusingly, here `state` means the entire application
// state being tracked by Redux... *not* CounterDisplay's state
return {
counter: state.counter
}
}
export default connect(mapStateToProps)(CounterDisplay)
So instead of exporting CounterDisplay itself, we export the HOC. In addition to counter, connect will also automatically insert the dispatch function into props so we can make use of it in the component. That's the behaviour you're seeing in the source you're reviewing.
const { dispatch } = this.props; is just deconstructing this.props.dispatch into a dispatch variable so it's used from props and where do they come to props? From react-redux connect:
export default connect(mapStateToProps)(SessionsNew);
connect is just Higher Order Component which basically connects your component with the store. As part of this process it puts dispatch into component's props
Edit:
The main idea is that connect is a function that takes whatever components and extends it's props with dispatch property (it returns another react components that wraps your component). You can also map some properties from state to your component and bind actions with dispatch using mapDispatchToProps and mapStateToProps
Just an example of destructuring assignment. See more here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

Using selectors with smart/dumb components in redux

Say I have a top most smart component called Forecast that looks like this:
function mapStateToProps(state) {
return {
dates: state.getIn(['forecast', 'dates']),
isFetching: state.getIn(['forecast', 'isFetching'])
};
}
export default connect(mapStateToProps, {
fetchForecast
})(Forecast));
Which wraps a Forecast component like this:
import { getSummary, getDayForecast } from '../selectors/selectors';
export default class Forecast extends Component {
render() {
const { dates, isFetching } = this.props;
return (
<div className="row">
{dates.map(date => (
<Weather
key={date}
date={date}
getSummary={getSummary}
getDayForecast={getDayForecast}
/>
))}
</div>
);
}
};
Here I am passing 2 selectors as props into a Weather component. The selectors look like this:
import { createSelector } from 'reselect';
import moment from 'moment';
import { fromJS } from 'immutable';
const getDay = (state, key) => state.getIn(['forecast', 'forecast']).find(x => x.get('id') === key);
export const getSummary = createSelector(
[getDay],
(day => {
const firstPeriod = day.get('periods').first();
return fromJS({
date: day.get('date'),
outlook: firstPeriod.get('outlook'),
icon: firstPeriod.get('icon')
});
})
);
export const getDayForecast = createSelector(
[getDay],
(day) => day.get('periods').map(period => fromJS({id: period.get('id') }))
);
I don't have to pass these selectors down as props, I could easily just reference them in the weather component but I am confused as to how I would use these selectors in the Weather component as the Weather component is also dumb and won't have any reference to state. I only want 1 container or smart component at the top which the child components call or get props passed down.
The only way I can see of making this work is to have an intermediatary WeatherContainer component that looks something like this:
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import Weather from '../components/Weather';
import { getSummary, getDayForecast } from '../selectors/selectors';
function mapStateToProps(state, ownProps) {
return {
summary: getSummary(state, ownProps.date),
detail: getDayForecast(state, ownProps.date)
};
}
export default(connect(mapStateToProps,{}))(Weather);
And I would call like this:
{dates.map(date => (
<WeatherContainer
key={date}
date={date}
getSummary={getSummary}
getDayForecast={getDayForecast}
/>
))}
This seems completely wrong to have to create a container component like this.
How can I make use of selectors in dumb components or how can I pass them down as props baring in mind that they also need reference to the state?
In your WeatherContainer mapStateToProps you use your selectors but you're still passing them down as props. This is not necessary.
Besides that, you should know that creating your container WeatherContainer is the right way to go about things. You should never give a selector to a component. They should always be used in mapStateToProps. React-Redux will reevaluate this when state changes and will tell React to update your components whenever the result is different. This is a very important point. If you just grab the state inside a component, whether using a selector or not, then React-Redux doesn't know you're using this data and won't we able to tell React to rerender when this data changes.
Now, a lot of people are confused on this matter. There are dumb components, which just display stuff, and container components, which do stuff, like make API calls or implement functionality of sorts. But when you take a dumb component and connect it to Redux, then this doesn't make for a smart or container component. It still only displays stuff. Even if you use mapDispatchToProps to feed it some event listeners, this still doesn't really make the component smart. It could become smart if it contains significant code in mapStateToProps or mapDispatchToProps I guess. But such is life. The line between these things is just blurry.
The Redux Way is to connect everything that needs data. You can certainly pass data down to children, just as in plain React, but you create a more performant app by connecting components. Still, it's up to you to decide. But it is still important that anywhere you grab data from the store, it should be put inside a mapStateToProps so React-Redux can keep an eye on the data. You can safely pass it from a parent to a child as long as the data came from mapStateToProps.
This means passing selectors to children is a no-no. Also, where's the child going to get the state to pass as a parameter to the selectors? It doesn't work well so it's not a good idea. Note that whenever you connect a component, you're not creating an entirely new component. Is just a simple wrapper. It should contain very little code in very few lines. This should not give you pause. Just go for it. connect those components.
I should also mention that you can connect your Weather component directly inside the weather.js file. Unless you're going to reuse it, there's not much need to keep the unconnected component around. For testing you can export the unconnected component with a named export. If later on you decide you need to reuse theWeather component, you can always easily separate the component and the connect call into separate files.

Resources