What is the difference between enzymes shallow render and instance method - reactjs

I do not understand how the following two lines are different
shallowRenderedComponent = shallow(<SomeComponent />)
shallowRenderedComponentInstance = shallowRenderedComponent.instance()
The enzyme docs are very vague and I could not find any comparison on the internet.
Thanks in advance

shallow returns a wrapper object that has all of the methods enzyme define's in its docs (e.g., find, setProps, etc)
The instance is directly accessing an instantiated object of your React component. That is, the methods available on the instance are those that you wrote for that class in your application code.
As an example, if your React component looks like the below, your shallowRenderedComponentInstance will give you access to handleClick
class Example extends React.Component {
handleClick = () {
console.log("I was clicked");
};
render() {
return (
<pre>Hello, World!</pre>
);
}
}

Related

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

Call Method on createClass result Should be simple

I would like to call a method on a random component after creating it but before rendering it. To perform child specific calculations for the parent prior to rendering the parent. A simple static should work.
class Container extends ReactWrapper{
render() {
const rClass = React.createClass(this.getCCArgs());
var newData = rClass.expectedUtilityFunction(data);
// render parent with new data.
return (<div {...this.props.data, ...newData}>
{rClass}
</div>);
};
};
Tried a number of ways and the utility method is always not found.
I could push things up the line logically and add a method to return the class used to create the react instance from the input data but I already have the react class instance.
React.createClass is deprecated and removed from React 16+. So I suggest stop tring to make it work.
Your code is good fit for High order component.
Below is sample code (I didn't tested it, so use it as hint only)
function WrappedComponent (Component, props) {
var newData = /* Here is good place for expectedUtilityFunction code. Don't put expectedUtilityFunction function into Component, put it here, in HOC body */
// render parent with new data.
return (<div {...props.data, ...newData}>
<Component/>
</div>);
}
And use HOC like this
class Container extends ReactWrapper{
constructor(props) {
supre(props);
// Assuming that this.getCCArgs() returns component
this.hoc = WrappedComponent (this.getCCArgs(), props);
}
render() {
return this.hoc;
}
}

how to redefine a component in React?

There is a spa for react/redux. There is a component of Brands. The Media component is similar to it, but the data is retrieved from another Ajax request. I'm trying to inherit from Brands, but for some reason the componentDidMount is launched from Brands. How to do it right?
class Media extends Brands {
loadData = async () => {
alert('sdfdf'); //not displayed
const { dispatch, dataList, clientId } = this.props;
if (!dataList && clientId) {
dispatch(mainLoaderActions.addBlockingRequest("loadMedia"));
const res = await mediaApi.getBrandsData(clientId);
dispatch(dataActions.setBrandsList(res));
dispatch(mainLoaderActions.deleteBlockingRequest("loadMedia"));
}
};
componentDidMount() {
alert('aaa'); //not displayed
this.loadData();
}
render() {...
React doesn't support class inheritance, hence your difficulty! See documentation here: https://reactjs.org/docs/composition-vs-inheritance.html There is an answer on a similar question here: componentDidMount method not triggered when using inherited ES6 react class with an example of 'react' way of achieving this.
It is possible to accomplish by using HOC (higher order components).
It will require to refactor both functions to reuse components common behavior in reactish way.
Check out this post from official react docs:
Higher-Order Components
A higher-order component (HOC) is an advanced technique in React for reusing component logic.

How do I test a callback of a React component wrapped in withRouter?

I'm using Jest and Enzyme to test a React project written in TypeScript. I have a component that is wrapped in a React-Router router, and which looks somewhat like this:
import { SomeButton } from './someButton';
import { RouteComponentProps, withRouter } from 'react-router';
const SomeButtonWithRouter = withRouter<{buttonCallback: () => void}>(SomeButton);
export class SomePage extends React.Component <RouteComponentProps<{}>, {}> {
constructor(props: {}) {
super(props);
this.someCallback = this.someCallback.bind(this);
}
public render() {
return (
<div>
<SomeButtonWithRouter buttonCallback={this.someCallback}/>
</div>
);
}
// This is the callback I want to test:
private someCallback() {
console.log('This is a callback');
}
Now I'm trying to write a test that calls someCallback and then makes some assertions. I've wrapped SomePage in a MemoryRouter to be able to test it:
it('should do something', () => {
const page = mount(<MemoryRouter><SomePage/></MemoryRouter>);
const cb = page.find('SomeButton').prop('buttonCallback'); // <-- this is undefined
});
As mentioned in the comment, unfortunately the buttonCallback prop is undefined when accessed like this. However, when I output page, it does say it is defined:
<withRouter(SomeButton)
onVerified={[Function bound ]}
and some lines below:
<SomeButton
history={ // ...
// ...
onVerified={[Function bound ]}
Both SomeButton and withRouter(SomeButton) don't work as selectors for Enzyme's find.
I'm not sure why that's the case; I am able to access a callback this way for another child component that is not wrapped in withRouter. I'm also not sure whether everything I'm doing is the right way to do them in the first place, so any pointers as to better ways of doing things are welcome.
Grr... As usual, a night of sleep helped me identify the problem - and it wasn't actually here. In case it helps anyone, I'll detail the mistakes I made.
First, the most useful thing to know: both const cb = page.find('SomeButton').prop('buttonCallback'); as well as const cb = page.find('withRouter(SomeButton)').prop('buttonCallback'); should work - although I'd go for the former, as then you don't need to know about the use of the router.
Second, the reason I thought it didn't work was because I was trying to output the result using toJson(page.find('SomeButton').prop('buttonCallback')) (using enzyme-to-json), which will happily convert that function to undefined.
And finally, and this is the dumbest thing - I didn't saw an effect from calling the callback because... I didn't actually call it. I merely assigned it const buttonCallback = page.find..., but had to follow that up with buttonCallback(). Oh, and also: there was a typo in my assertion afterwards.
I know, dumb. Feel free to laugh at me when you come across this issue in six months.

Trying to render a new instance in ReactJS

As an example (real tried code)
I have a component of which I want to initiate a NEW instance for rendering.
import React, { Component } from 'react';
export default class TinyObject extends Component {
constructor(props) {
super(props);
console.log("TinyObject constructor");
}
render() {
console.log("TinyObject render");
return (
<div>HEY THIS IS MY TINY OBJECT</div>
);
}
}
Then in main App constructor I do the following:
var myTinyObject = new TinyObject();
var myArray = [];
myArray.push(myTinyObject);
this.state = {testing: myArray};
Then a created a function to render this:
renderTest()
{
const {testing} = this.state;
const result = testing.map((test, i) => {
console.log(test);
return {test};
});
}
And I call this from the App render function like this:
render() {
const { gametables, tableActive } = this.state;
console.log("render");
return <div><div>{this.renderTest()}</div></div>;
}
It runs, no errors.
I see console log of the following:
console.log("TinyObject constructor");
console.log(test);
But I don't see console log of the TinyObject render nor do I see the render output.
Thanks to lustoykov answer I got a little further
JSX: var myTinyObject = <TinyObject />;
works!
but in the real app I add a little more and don't know how to do it here.
return <GameTable key={'gt'+index} data={table} settings={this.settingsData} sendTableNetworkMessage={this.sendTableNetworkMessage} />
this is the way I was rendering; and I needed more instances of GameTable
now the question is; how do I add the arguments like data & settings to myTinyObject.
thanks for helping so far.
You don't manually instantiate react component, use JSX or createElement. For instance
via JSX
var myTinyObject = <TinyObject prop1={prop1} prop2={prop2} />;
via React.createElement
var myTinyObject = React.createElement(TinyObject, { prop1, prop2 }, null);
I would definitely check out some tutorials and how React works at a basic level. You aren't really going to call your react components like you would normally do in javascript since the render function returns jsx.
Fundamentally, React is what is called a single page application. That means that your browser will load up a single html file with a div. Now that div will be where React performs its magic by using Javascript to change stuff around.
It is easiest for me to think of React as a tree. You create these components that you place on the DOM or in your HTML and React will add and remove them downwards. For instance, take a look at this picture of twitter.
So first the Feed component is going to be put on the DOM. Then the Feed component will render the Tweet components. So as you can see the rendering goes in one direction, downwards.
Now, as you can see your render methods are not returning javascript. It is returning something that looks like HTML but we call it JSX. That means we want to render it a little differently with our react classes.
If we have a child component:
class Child extends React.Component {
render() {
return <h1>Hello, I am inside the parent component</h1>;
}
}
We can call the render method like this:
class Parent extends React.Component {
render() {
<Child /> //This is how I use the Child class
}
}
Now the reason why react is so performant is that the child cannot be re-rendered unless we do 1 of two things:
It is a component with a state and we call a method setState()
We pass down new props to a child component from the parent component
You can read about it here
Now the only way to get React to call that render function again is by doing those two things.

Resources