ES6 React Redux syntax clarification - reactjs

I'm new to ES6 and Redux. Im looking at some code and trying to understand what is going on in this new ES6 syntax.
I feel like this may be simple but i am not understanding it and it might help someone else in a similar position to me.
i want to know how the following code is creating a react element. im familiar with the React.createClass method, but that doesnt seem to be stated here or at least not explicitly. i can see React is imported, but it isnt mentioned in the rest of the code. so then how the FileTable get turned into a react component?
I can see the const variable FileTable seems to contain what would usually go in the render method of React.createClass, but if that is the case, where would methods like componentDidMount, componentDidUpdate, etc be defined?
Any help on this is greatly appreciated.
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import * as actions from '../actions';
const FileTable = ({ fileList, getFileList}) => {
return (
<ul className="filterable-table">
{fileList.map((file)=><li>{file.fileName}</li>)}
</ul>
);
};
FileTable.propTypes = {
fileList: PropTypes.array,
};
const mapStateToProps = (state) => {
return {
fileList: state.fileList
};
};
const mapDispatchToProps = (dispatch) => {
return {
getFileList: () => dispatch(actions.getFileList())
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(FileTable);

You can create react components in 3 ways - React.createClass, ES6 class or
Stateless (pure) function component. This is a stateless component, which means that it doesn't have state, life cycle methods (like componentDidMount or componentDidUpdate), and refs, and as you surmised it's similar to the render method of a react class.
Whenever you need a purely representational dumb component you can use a stateless component, due to its brevity. It goes nicely with redux, as the connect create a smart component that wraps the stateless method.
Regarding performance, stateless components don't have any performance gain over ES6 class component without state. However, Facebook stated that in the future there will be some optimizations.

It doesn't have to be declared here as a React component; React knows about pure functions.
Pure functions don't need to inherit from Component. They're not appropriate for all component types, but for simple HTML renders they're preferred (e.g., see eslint-plugin-react prefer-stateless-function.
Pure functions don't have component lifecycles, associated methods, etc.

Related

How should I improve this behavior in React?

in my company we are using ReactJS to develop our website. We also have legacy code in jQuery (I know, we are trying to change everything to React). My problem is that we have some global functions that we have to pass throughout all the component tree. For instance, we have a control function that we have to pass throughout 8 components, but only the last one actually calls it.
So, I wonder if there's a way to avoid this problem. Another problem is that we have several react trees on the page, because as I said, we have some legacy code in jQuery. Any ideas/suggestions?
(pls if this question does not belong in this forum let me know)
So you have to create yout context like this:
import React from "react";
const YourContext = React.createContext({ func: null });
export default YourContext ;
then in your parent component you can initialize it and make it available in child components:
import React from "react";
import YourContext from "./YourContext";
const YourParentComponent = () => (
<YourContext.Provider value={{ func: () => {} }}>
....
</YourContext.Provider>
);
and in your child components you can use it:
import React, { useContext } from "react";
import YourContext from "../YourContext";
const YourChildComponent = () => {
const { func } = useContext(YourContext);
Have a look at React Context, it will allow you to pass data through the components tree without passing down the props.

Getting props through HOC when mounting in Enzyme

I am trying to test some code that uses firebase. I am implementing the firebase-mock library. The problem I'am encountering now is that most all the components I should test get the firebase instance from a HOC (I have a class with the firebase methods I am using that is provided through the context API in the index.js and consumed via a withFirebase HOC, the wrapped component will have firebase in its props).
In this case the code I am trying to test is the following:
// mount.js
import React, { Component } from 'react';
import { withFirebase } from '../../components/Firebase';
class mount extends Component {
state = {
data: null,
};
ref = this.props.firebase.db.ref('/testing');
componentDidMount() {
// Fetch from testing ref
this.ref.on('value', snap => {
this.setState({ data: snap });
});
}
componentWillUnmount() {
this.ref.off('value');
}
render() {
return <div />;
}
}
export default withFirebase(mount);
In my test file I'm doing the following:
describe('Component mount.js', () => {
it.only('fetches', () => {
const wrapper = mount(<Mount />);
console.log(wrapper.prop());
console.log(wrapper.state().data);
});
});
This fails because this.props.firebase is null.
How could I solve this so that I can continue and finally mock firebase calls as i was intending.
I'm guessing that the problem is how to use the Context API in Enzyme, but I'm not sure.
The message you are getting is because enzyme.mount() is returning the withFirebase HOCcomponent, not the <Mount> component that you expect. what you need to do is "find" the contained component. In your example I think myContainedComponent = wrapper.find('Mount') would return the component that you could then do console.log(myContainedComponet.props); There are a lot of answers to similar questions about using Enzyme to test HOC and their enclosed components. I am using React 17 which is not supported by Enzyme.mount() so I have to use shallow. Again there are answers related to doing wrapper = shallow(shallow(<BurgerBuilder/>).get(0)); but these don't work for my setup either.
What is working for me is:
wrapper = shallow(<BurgerBuilder/>);
instance = wrapper.find('BurgerBuilder').dive().instance();
jest.spyOn(instance, 'addIngredientHandler');
NOTE: this is the export for the BurgerBuilder component.
export default withErrorHandler(BurgerBuilder, axiosOrders);
In this example, instance holds the class instance of the contained component rather than the HOC, withErrorHandler.
One of the interesting things about my example is that 'addIngredientHandler' is an arrow function in my class. There are other threads that talk about the complexities of testing class member arrow functions in React. (BTW, you do not need to do instance.forceUpdate(); )
In the interest of full disclosure, I am building my testing skills as I learn React. The components I am testing were developed while running through the Udemy course: React - The Complete Guide (incl Hooks, React Router, Redux)

Type safe handling of functional component props injected by an HOC

TL;DNR: I'm using TypeScript 3.3.3. Is there a better way to declare props I need that are injected from an HOC, without making them visible to code consuming my component?
Consider a basic component that is decorated with the withNamespaces HOC. The library and HOC used is arbitrary, I've run into this problem with any components that follow this pattern. It's also a bit of a problem with class components, but I'll focus on functions here.
// MyComponent.tsx
import * as React from 'react'
import { withNamespaces, WithNamespaces } from 'react-i18next'
const MyComponent: React.FunctionalComponent = ({ children, t }) => (
<a title={t('my translated text')}>{children}</a>
)
export default withNamespaces('my-component')(MyComponent)
I've got a second file that contains tests for my component.
// MyComponent.spec.tsx
import * as React from 'react'
import { shallow } from 'enzyme'
import MyComponent from './MyComponent'
it('should render', () => {
const wrapper = shallow(<MyComponent>Test</MyComponent>)
expect(wrapper.toExist()).toBeTruthy()
})
Now this won't compile because t is not defined in my props. I can try fixing this a number of ways. In this example, the third-party library gives us a WithNamespaces type that defines t, and a bunch of other things that withNamespaces injects into our component, which we can use as or merge with our props type definition.
const MyComponent: React.FunctionalComponent<WithNamespaces> = ({children, t}) => ( // ...
Now MyComponent compiles and gives me nice type safety as to my possible props. However, now my test file is angry because I haven't provided values for props the component definition expects, for example t. However, we know this is going to get injected by the HOC, so creating a mock or providing this prop with a value of some garbage is just confusing and unnecessary extra work to fix type problems.
// type is missing the following properties from WithNamespaces: t, etc., etc.
const wrapper = shallow(<MyComponent>Test</MyComponent>)
I can fudge that by making my component's props partial ala FunctionalComponent<Partial<WithNamespaces>>, but now I've got to conditionally check those props I need or use t! (not-null assertion operator), and these seem unnecessarily annoying, melts the brains of people new to TS, and seems a little smelly.
I can also just cast the props inside my render function (or in classes, any method that is accessing props) to hide the injected props from my consumers:
const MyComponent: React.FunctionalComponent = (props) => {
const { children, t } = props as WithNamespaces
return (
<a title={t('my translated text')}>{children}</a>
)
}
This is a little handwavy and inelegant, though. There are a multitude of other ways, like casting to any and back to something that doesn't reference WithNamespaces, etc., but surely there's a better way to do this?
Misc
withNamespace does have a definition that uses the Omit pattern to exclude the props in WithNamespaces from the returned type, but that doesn't seem to be working, at least with functional components.

Is it good practice to have just one subscriber at root level when writing a React/Redux application?

Last year I wrote a pretty sizeable application using React and Redux that had only one subscriber at the root level. The pattern was (roughly) as follows:
const myApp = () => {
store.subscribe(render);
render();
};
module.exports = myApp;
const render = () => {
const rootDOMElement = document.getElementById('root');
ReactDOM.render(
<section className="myApp">
...
</section>,
rootDOMElement
);
};
Essentially, I "rendered the whole thing every time", safe in the knowledge that React would on the whole only re-render the descendant components that actually needed to be re-rendered. This worked exceptionally well, even when the application scaled to thousands of component instances.
Now, however, I'm wondering whether this is sound advice to pass on to others. I have found no clear guidance (although admittedly I could have looked harder). Generally I get the impression that most people write many components that subscribe to the store these days. See, for example:
https://www.reddit.com/r/javascript/comments/6hperk/i_use_react_and_redux_but_never_reactredux_what/dj0fywb/
But isn't the whole idea of React, or at least one of the ideas, that you are not supposed to worry about what goes on under the hood? Subscribing at the root level works well precisely because React is smart enough to know not to re-render everything, right? Or am I missing the point? Again it's worth pointing out that my application ran exceptionally well, I never had to give performance a second thought.
When you creating app, its performance is not the only thing to think about. Besides many other, there is clarity and code obvious, ease of development and maintaining.
If you use connect function from react-redux it becomes completely clear to any who see your component what reducer and what attribute of that reducer will update that component.
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
MyComponent.propTypes = {
status: PropTypes.number,
};
class MyComponent extends Component {
render() {
return (
<div> { this.props.status } </div>
);
}
}
function mapStateToProps(state) {
return {
status: state.someReducer.status,
};
}
function mapDispatchToProps(dispatch) {
return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
Also it is important that you may use PropTypes for type checking of reducer values that pass to props, what facilitates component testing.
So I think, no. It is not good practice.
Good practice is to have so many subscribers, how many components should be subscribed to some reducers

JSDoc Tag Support for React HOC (Higher-Order Component)

What is the proper way to document a React Higher-Order Component using JSDoc? There aren't, of course, any React-specific tags built-in - so what would be the proper approach?
To document a high-order component with JSDoc, you would follow the standard as laid out below. To clarify, the documentation is usually found where the higher-order component is defined and not necessarily where it's used. If you want to document where it's used, that can be documented in that component's JSDocs as a #description, #see, #link, or other relevant tags.
import React, { useState } from 'react';
import Async from 'react-async';
import { withTheme } from 'design'; // Contains the JSDoc for this HOC.
import { getName } from 'api';
/**
* Component to render a greeting to someone!
*
* #component
* #param {string} userId The ID of the user to greet
*/
export function Hello({ theme, userId }) {
return (
<Async promiseFn={getName} userId={userId}>
<Async.Fulfilled>
{(data) => <p>Hello {data.name}!</p>}
</Async.Fulfilled>
</Async>
);
};
export default withTheme(Hello);
Documentation with React, and code in general, is always interesting. There are several ways and along with it, advantages and disadvantages of each. Ask yourself what it's going to be used for? Creating a documentation website, sharing between teammates, developers only, etc.? That being said, the most common ways to purely document are JSDoc and Markdown.
Markdown (e.g., Material UI)
MarkdownX (MDX
There are other ways to visualize components that have built-in documentation functionality usually based around Markdown or JSDoc as well. This becomes extremely useful when working within a team or publishing packages.
Bit (Bit Documentation)
Storybook (Storybook for MD)
React StyleGuidist (StyleGuidist Docs)
The HOC pattern is a really important tool for code reuse when building UIs in React. Prop types are helpful for catching bugs before they reach production.
Writing HOCs that properly handle the prop types of the components that they wrap, though, is difficult and requires a lot of boilerplate code. Ideally, an engineer should not shy away from moving logic to an HOC because it is too verbose to write one.
To solve this problem, react-create-hoc provides a function that implements much of this boilerplate. It allows HOCs to be created with only a straightforward function that simply wraps a component in a new component.
Usage
import React from 'react';
import PropTypes from 'prop-types';
import createHOC from 'react-create-hoc';
function WelcomeMessage({ name }) {
return <div>{greeting}, {name}!</div>;
}
WelcomeMessage.propTypes = {
greeting: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
};
const withModifiedName = createHOC(
'withModifiedName',
(ComponentToWrap, nameModifier) => {
function WithModifiedName({ nameProvider, ...rest }) {
return (
<ComponentToWrap
name={nameModifier(nameProvider())}
{...rest}
/>
);
}
WithModifiedName.propTypes = {
nameProvider: PropTypes.func.isRequired,
};
return WithModifiedName;
},
{
factory: true,
passedProps: ['name'],
},
);
// WrappedWelcomeMessage has the following prop types:
// {
// greeting: PropTypes.string.isRequired,
// nameProvider: PropTypes.func.isRequired,
// }
const WrappedWelcomeMessage = withModifiedName(
// nameModifier param
name => name.toUpperCase(),
)(WelcomeMessage);
// Renders a div containing, "Rise and shine, MR. FREEMAN!"
ReactDOM.render(
<WrappedWelcomeMessage
greeting="Rise and shine"
nameProvider={() => 'Mr. Freeman'}
/>,
document.getElementById('root'),
);

Resources