I'm testing Hero component using jest & enzyme. I thought to my mind that I can do the same thing in the two ways.
For example, I want to get a component's state.
test('Test description', () => {
const element = shallow(
<Hero />
);
// 1
expect(element.state()).toBeTruthy();
// 2
expect(element.instance().state).toBeTruthy();
});
I have two variants to write this code: using .instance().state or .state(). Probably there are recommendations how to write code like that?
state() is a shortcut for instance().state that provides meaningful error message in case it's called on wrong wrapper.
Since state() exists in Enzyme API, it's intended to be used for this purpose. It takes less characters to type than instance().state.
Related
I have a very large and complex React application. It is designed to behave like a desktop application. The interface is a document style interface with tabs, each tab can be one of many different type of editor component (there are currently 14 different editor screens). It is possible to have a very large number of tabs open at once (20-30 tabs). The application was originally written all with React class components, but with newer components (and where significant refactors have been required) I've moved to functional components using hooks. I prefer the concise syntax of functions and that seems to be the recommended direction to take in general, but I've encountered a pattern from the classes that I don't know how to replicate with functions.
Basically, each screen (tab) on the app is an editor of some sort (think Microsoft office, but where you can have a spreadsheet, text document, vector image, Visio diagram, etc all in tabs within the same application... Because each screen is so distinct they manage their own internal state. I don't think Redux or anything like that is a good solution here because the amount of individually owned bits of state are so complex. Each screen needs to be able to save it's current working document to the database, and typically provides a save option. Following standard object oriented design the 'save' function is implemented as a method on the top level component for each editor. However I need to perform a 'save-all' function where I iterate through all of the open tabs and call the save method (using a reference) on each of the tabs. Something like:
openTabs.forEach((tabRef) => tabRef.current.save());
So, If I make this a functional component then I have my save method as a function assigned to a constant inside the function:
const save = () => {...}
But how can I call that from a parent? I think the save for each component should live within that component, not at a higher level. Aside from the fact that would make it very difficult to find and maintain, it also would break my modular loading which only loads the component when needed as the save would have to be at a level above the code-splitting.
The only solution to this problem that I can think of is to have a save prop on the component and a useEffect() to call the save when that save prop is changed - then I'd just need to write a dummy value of anything to that save prop to trigger a save... This seems like a very counter-intuitive and overly complex way to do it.... Or do I simply continue to stick with classes for these components?
Thankyou,
Troy
But how can I call that from a parent? I think the save for each component should live within that component, not at a higher level.
You should ask yourself if the component should be smart vs dumb (https://www.digitalocean.com/community/tutorials/react-smart-dumb-components).
Consider the following:
const Page1 = ({ onSave }) => (...);
const Page2 = ({ onSave }) => (...);
const App = () => {
const handleSavePage1 = (...) => { ... };
const handleSavePage2 = (...) => { ... };
const handleSaveAll = (...) => {
handleSavePage1();
handleSavePage2();
};
return (
<Page1 onSave={handleSavePage1} />
<Page2 onSave={handleSavePage2} />
<Button onClick={handleSaveAll}>Save all</button>
);
};
You've then separated the layout from the functionality, and can compose the application as needed.
I don't think Redux or anything like that is a good solution here because the amount of individually owned bits of state are so complex.
I don't know if for some reason Redux is totally out of the picture or not, but I think it's one of the best options in a project like this.
Where you have a separated reducer for each module, managing the module's state, also each reducer having a "saveTabX" action, all of them available to be dispatched in the Root component.
For rendering smaller components/jsx within a bigger component, there are multiple approaches that one can follow. For example, consider this:
Method 1:
function BigComponent(props) {
const renderSmallComponent1 = () => <div>{props.a}</div>;
const renderSmallComponent2 = () => <div>{props.b}</div>;
return (
<div>
{renderSmallComponent1()}
{renderSmallComponent2()}
</div>
)
}
Method 2:
function BigComponent(props) {
const smallComponent1 = <div>{props.a}</div>;
const smallComponent2 = <div>{props.b}</div>;
return (
<div>
{smallComponent1}
{smallComponent2}
</div>
)
}
Method 3:
function SmallComponent1({ a }) {
return <div>{a}</div>;
}
function SmallComponent2({ b }) {
return <div>{b}</div>;
}
function BigComponent(props) {
return (
<div>
<SmallComponent1 a={props.a} />
<SmallComponent2 b={props.b} />
</div>
)
}
I am just trying to understand the difference in these 3 in terms of
dev experience,
how the framework treats them,
are there any performance optimizations,
are there differences in runtime behaviours in all of these?
Is either one better to use in certain scenarios?
These are the things that I understand:
in Method 3, all SmallComponent are React components which are rendered in another component, so they would have a component lifecycle, while in method 1 and 2, they are simple jsx, which does not have lifecycle, so they would not be mounted / unmounted as React components
in Method 2, we would be eagerly evaluating the JSX as it is directly a variable, while in method 1, it would only be evaluated when the function is called in render. So, in case, we have any conditional rendering, the eager evaluation might just be wasteful.
A few other helpful articles:
https://medium.com/missive-app/45-faster-react-functional-components-now-3509a668e69f
https://kentcdodds.com/blog/dont-call-a-react-function-component
UPDATE: it seems observation 1 is incorrect as all 3 of them would still be rendered as react components, and hence would have a component lifecycle. So react would mount/unmount them.
UPDATE 2: No, observation 1 is correct, method 1 and 2 are both treated as regular jsx as part of the BigComponent and they are not treated as react component which have a lifecycle.
UPDATE 3:
There is another method Method 4:
function BigComponent(props) {
const SmallComponent1 = () => {
return <div>{props.a}</div>;
}
const SmallComponent2 = () => {
return <div>{props.b}</div>;
}
return (
<div>
<SmallComponent1 />
<SmallComponent2 />
</div>
)
}
this is similar to Method 3, but Method 3 vs Method 4 is slightly different in execution, when debugging through dev tools.
Method 2:
function BigComponent(props) {
const smallComponent1 = <div>{props.a}</div>;
const smallComponent2 = <div>{props.b}</div>;
return (
<div>
{smallComponent1}
{smallComponent2}
</div>
)
}
If you want to a large UI into seperate smaller UI, this method will give you best performance because
It is still just one big UI component.
react just have to solve variable references.
while re-rendering, BigComponent,smallComponent1 and smallComponent2 are rendered together as single unit.
smallComponent1 and smallComponent2 cannot have their own state, life cycles and hooks.
smallComponent1 and 2 needs to be re-initialized everytime Bigcomponent state is changed. So it is good practise to wrap them with useMemo() if the result of those smallComponents are coming from an expensive computation.
Method 3:
function SmallComponent1({ a }) {
return <div>{a}</div>;
}
function SmallComponent2({ b }) {
return <div>{b}</div>;
}
function BigComponent(props) {
return (
<div>
<SmallComponent1 a={props.a} />
<SmallComponent2 b={props.b} />
</div>
)
}
React needs to resolve reference as well as execute the function after resolving the reference.
It is a composition of react's actual child components into a large Component.
Child components are allowed to have their own hooks.
Child components are not re-initialized but are re-rendered if BigComponent state is changed.
There is chance of SmallComponent1 and SmallComponent2 getting re-rendered multiple times on BigComponents rendering once if small components are updating thier own state based on props change in parents.
if each SmallComponents are supposed to use multiple props which state of BigComponents, Keeping SmallComponents outside BigComponent does offer good developer experience.
I hope Method 1 and Method 4 can also be understood using these above points.
Note: childcomponents stored in variable and childcompoents as function becomes tricker if your application logic is using ref or DOM element for maininting focus or anchor point of rendering.
Have you taken a look at the compiled JS in a React project?
JSX tags are essentially transformed in to React.createElement statements. You can read the docs here. Essentially the syntax is:
React.createElement(FunctionOrClassComponent, { props }, ...children)
In all three of your examples this would take place. In all three examples, the smaller components are functional components rather than class components. That is to say, they don't have the React lifecycle methods of a class component, but they can use equivalent React hooks - should you want to.
Edited: Evaluation (instantiation and rendering) depends on your render logic. If you have conditional rendering statements or your functions return null (or less content) based on certain conditions, then obviously you're doing less work. And as you rightly pointed out in the comments below, when you assign a JSX.Element to a variable, that is evaluated inline rather than as a result of a function - so that happens immediately.
To me, all three are valid approaches. To address your questions:
dev experience,
for small components with minimal state, functional components as variables or lambdas are convenient to write and easily read/parsed when revisiting code at a later date. When a component becomes more complex, you may have to reconsider how it's written and perhaps use Class components.
how the framework treats them,
to my knowledge the framework treats all three of your examples the same in terms of compilation. I'm unsure about rendering optimisation.
are there any performance optimizations,
your examples don't depict anything computationally onerous so performance optimization options are not so obvious
are there differences in runtime behaviours in all of these?
they are all translated to React elements, monitored for props changes, and re-rendered if parents re-render (if things like React.memo are not employed) -- there may be differences vs class-based elements, but I would guess that the runtime differences between your three examples are minimal
Is either one better to use in certain scenarios?
The differences between all three are more a matter of standards or etiquette than functional outcome. As a developer, I would be able to read and understand all three, but working in a team - I would want to see a standard approach.
I need some advice on how to write tests for React component. I have 2 approaches in my mind, feel free to suggest more.
I have a component App which renders a ComplexSearchBox. I pass this ComplexSearchBox a prop onSearch, the value of this prop is a function. This function is invoked by ComplexSearchBox at various user interactions like when the user hits enter on the input box or clicks the search button.
const App = () => {
return <ComplexSearchBox onSearch={query => console.log(query)}/>;
};
I want to write tests for App component. I'm using Enzyme to write tests.
I'm following some principles of React Testing Library.
I'm mounting the component. So this will render all children as well. I don't want to render ComplexSearchBox so I'll mock it.
This is where my problem is. I have 2 approaches in my mind.
I can get the props of ComplexSearchBox and invoke the method directly with the required parameters.
jest.mock('Path To ComplexSearchBox', function ComplexSearchBox() {
return null;
});
describe('App', () => {
describe('when search button is clicked', () => {
it('should log to console by invoking prop method', () => {
const wrapper = mount(<App/>);
wrapper.find('ComplexSearchBox').props().onSearch('My random test query');
//expect something
});
});
});
I can mock the ComplexSearchBox and return a simplified version of it. Now I can type the query in an input box and then click a button to submit.
jest.mock('Path To ComplexSearchBox', function ComplexSearchBox({onSearch}) {
const [query, setQuery] = useState('Sample Search Query');
return <div>
<input value={query} onChange={setQuery}/>
<button onClick={() => onSearch(query)}/>
</div>;
});
describe('App', () => {
describe('when search button is clicked', () => {
it('should log to console by clicking', () => {
const wrapper = mount(<App/>);
wrapper.find('input').simulate('change', {target: {value: 'My random test query'}});
wrapper.find('button').simulate('click');
//expect something
});
});
});
I see value in the second approach. However, I'm not sure if it is worth the effort of creating a simplified version every time I have to interact with a child component.
The benefit of the second approach is that
It decouples the code from tests. My tests don't have to know which method to invoke with what parameter when the user wants to execute a search. Mock knows which method to invoke but that is at one place and not spread across all the tests.
I find tests to be more readable and behaviour oriented when written this way.
This mock can be extracted out and used at multiple places. Making writing tests easier.
Any method sequencing can be abstracted in the mock component. Like if I modify the ComplexSearchBox as below.
const App = () => {
return <ComplexSearchBox preProcess={()=>{}} onSearch={query => console.log(query)} postProcess={()=>{}}/>;
};
jest.mock('Path To ComplexSearchBox', function ComplexSearchBox({preProcess, onSearch, postProcess}) {
const [query, setQuery] = useState('Sample Search Query');
const search = (query) => {
const preProcessedQuery = preProcess(query);
const searchedQuery = onSearch(preProcessedQuery);
postProcess(searchedQuery);
};
return <div>
<input value={query} onChange={setQuery}/>
<button onClick={() => search(query)}/>
</div>;
});
Though I'm not very sure if the last benefit is really a benefit. As now my mock is aware of the lifecycle of ComplexSearchBox. But on the other hand, this mock will be written only once and will save me from calling those 3 methods one after the other in a lot of tests.
I could also argue that a component test written with approach one should not really care about the method sequencing as that is ComplexSearchBox responsibility.
Those 3 methods do have a tight coupling as one's output is next one's input. And now I'm borderline integration testing these 2 components.
I could also have 3 buttons which have onClick to run those 3 methods and now I can test them individually.
I'm not really sure which approach is better. I'm leaning a bit towards approach 2 because it makes my tests less dependent on implementation.
I'd appreciate any advice on this and if you have another way to test this scenario then please share.
I don't have an exact answer for you, but I highly suggest reading this article:
https://kentcdodds.com/blog/why-i-never-use-shallow-rendering
In it, you will find arguments against shallow rendering, and in favour or integration tests in React.
The points you made are all valid, if you choose the route of unit testing, therefore mocking all subcomponents of the <App /> component, you will be coupling your tests to the current implementation of those subcomponents, and anytime you change those subcomponents, even if the refactor doesn't change the behaviour, you run the risk of breaking the <App />s test.
I don't believe there is a way around it when you are dealing with mocks, so I would suggest considering the article above and not mocking anything, which might run the tests a little slower, but it probably won't be a big deal most of the time!
Intro: I'm a bit confused with React. I've seen articles saying that React components are just functions that receive the props and render to the virtual DOM. What I see, however, is that they are full-blown stateful monsters and I have found no way to treat them like functions.
The question: Why is each usage of a React component wrapped in React.createElement? Why can't I use new MyComponent() instead? It looks pretty similar when I do it in DevTools. Why is React.createElement needed at all, given that components are created using React.createClass? It looks like redundant to me.
Edit: this looks relevant: https://gist.github.com/sebmarkbage/ae327f2eda03bf165261
Edit #2: This is related, but not a duplicate of React.Component vs React.createClass, that question asks about creating classes. I'm not asking about creating new component classes, I'm asking about creating instances (elements) of that classes.
I think I found the answer here:
In React 0.12, we're making a core change to how React.createClass(...) and JSX works.
(...)
Currently var Button = React.createClass(...) does two things. It
creates a class and a helper function to create ReactElements. It is
essentially equivalent to this:
class ButtonClass { }
function ButtonFactory(...args) { return
React.createElement(ButtonClass, ...args); }
module.exports = ButtonFactory; ```
Then you access this in the consuming component by invoking the
ButtonFactory.
var Button = require('Button');
class App { render() {
return Button({ prop: 'foo '}); // ReactElement
} }
Conceptually this is the wrong model. The source component should not
be responsible for the output of App.
There are a few problems with this:
ES6 classes can't be directly exported, they need to be wrapped.
There's no convenient way to access the actual class and it's confusing which one you're using.
Static methods are wrapped in helpers that are not real function. As a convenience.
Auto-mocking destroys the factory so there is no way to test the result of render without disabling mocking.
Factories can be wrapped by other factories that returns something different than ReactElements. Making testing and optimizations
impossible.
Languages with specialized features for object management have to defer to React instead of using the built-in features.
How do people typically approach having "global" data in a React application?
For example, say I have the following data for a user once they're logged into my app.
user: {
email: 'test#user.com',
name: 'John Doe'
}
This is data that almost any component in my app might like to know about - so it could either render in a logged in or logged out state, or perhaps display the users email address if logged in.
From my understanding, the React way of accessing this data in a child component is for a top level component to own the data, and pass it to child components using properties, for example:
<App>
<Page1/>
<Page2>
<Widget1/>
<Widget2 user={user}/>
</Page2>
</App>
But this seems unwieldy to me, as that would mean I'd have to pass the data through each composite, just to get it to the child that needed it.
Is there a React way of managing this type of data?
Note: This example is very simplified - I like to wrap intents up as composites so implementation details of entire UI features can be drastically changed as I see fit.
EDIT: I'm aware that by default, calling setState on my top level component would cause all child components to be re-rendered, and that in each child component I can render using whatever data I like (e.g. global data, not just state or props). But how are people choosing to notify only certain child components that they should be rendered?
Since I originally answered this question, it's become apparent to me that React itself doesn't support "global" data in any sense - it is truly meant to manage the UI and that's it. The data of your app needs to live somewhere else. Having said that, it does now support accessing global context data as detailed in this other answer on this page. Here's a good article by Kent Dodds on how the context api has evolved, and is now officially supported in React.
The context approach should only be used for truly global data. If your data falls into any other category, then you should do as follows:
Facebook themselves solve this problem using their own Flux library.
Mobx and Redux are similar to Flux, but seem to have more popular appeal. They do the same thing, but in a cleaner, more intuitive way.
I'm leaving my original edits to this answer below, for some history.
OLD ANSWER:
The best answer I've found for this so far are these 2 React mixins, which I haven't had a chance to try, but they sound like they'll address this problem:
https://github.com/dustingetz/react-cursor
and this similar library:
https://github.com/mquan/cortex
MAJOR NOTE: I think this is a job for Facebook's Flux, or something similar (which the above are). When the data flow gets too complex, another mechanism is required to communicate between components other than callbacks, and Flux and it's clones seem to be it....
Use the React Context Property This is specifically for passing global data sets down the chain without explicitly forwarding them. It does complicate your Component lifecycle functions though, and note the cautions offered on the page I've linked.
You can use the React Context API for passing global data down to deeply nested child components. Kent C. Dodds wrote an extensive article on it on Medium React’s ⚛️ new Context API. It'll help in getting a better understanding of how to use the API.
I think React.createContext() is perfect solution for your purpose.
React will re-render only components, that listen context changes with useContext hook.
Here is a simple snippet for your code:
export const CurrentUser = React.createContext({})
const App = () =>
{
const User = getUser() // any authorisation method
return <>
<CurrentUser.Provider value={User}>
<App>
<Page1/>
<Page2>
<Widget1/>
<Widget2/>
</Page2>
</App>
</CurrentUser.Provider>
</>
}
const Widget2 = () =>
{
const User = useContext(CurrentUser)
return <>{User?.name}</>
}
In case if you want to control re-renders directly, you can use React.memo in nested components. For example, if you need re-render component only after specific attribute change.
Also, with nesting context values, you can reach good flexibility of your app. You can pass different context values for different part of your application.
export const CurrentUser = React.createContext({})
const App = () =>
{
const User = getUser() // any authorisation method
const AnotherUser = getAnotherUser() // any authorisation method
return <>
<CurrentUser.Provider value={User}>
<App>
<Page1/>
<CurrentUser.Provider value={AnotherUser}>
<Page2>
<Widget1/>
<Widget2/>
</Page2>
</CurrentUser.Provider>
</App>
</CurrentUser.Provider>
</>
}
const Widget2 = () =>
{
const User = useContext(CurrentUser)
return <>{User?.name}</>
}
What's wrong with just passing data all the way down the component chain via rendering all children with {...restOfProps}?
render(){
const {propIKnowAbout1, propIKnowAbout2, ...restOfProps} = this.props;
return <ChildComponent foo={propIKnowAbout1} bar={propIKnowAbout2} {...restOfProps}/>
}
There is Reactn https://www.npmjs.com/package/reactn
You use this.global and this.setGlobal to get and set the global state same as you do with the local state.
To be able to do so you only need to
import React from 'reactn';