To make e2e testing easier I would like to add to each react component data-component= attribute with component name. I would like to have it done "automatically" (without adjusting render() functions everywhere).
Anyone knows how to do it reliably for both class and function based components?
Component name is set via static property displayName for each component. You need to set it manually.
Create hoc (higher order component), to wrap component with div (or any other html tag) which will have required attribute.
const withComponentName(WrappedComponent) => {
const displayName = WrappedComponent.displayName || WrappedComponent.name || 'UnnamedComponent';
return props => (
<div data-component={displayName}><WrappedComponent {...props} /><div>
)
}
Wrap all component export statements with created hoc.
export default withComponentName(YourShinyComponent)
Another option is to use this Webpack plugin to do it for you:
https://github.com/lemonmade/babel-plugin-react-component-data-attribute
If you're using create-react-app:
If you've ejected already then just follow the docs on the plugin's page ☝️
However, if you have not ejected already, then you can use either of these solutions to customize your build for a create-react-app project:
https://github.com/arackaf/customize-cra
https://github.com/timarney/react-app-rewired/
Related
You can get, reference here in this StackBlitz Link
I have one folder file todoState.ts in models folder of project. This todoState.ts used for managing global state of application using custom hooks. I need to perform following tasks on global todoState.ts..
Add new State
Remove state
update state
here is code of todoState.ts.
import { useState, useEffect } from "react";
const todoState = (todo?, callback?) => {
const [todos, setTodos] = useState([todo]);
useEffect(()=>{
setTodos(todo);
},[])
return [{todos, setTodos}];
}
Now, I have Two user defined components which are dependent on globalState. which are 1. <TodoForm /> and <TodoListLineItem />
Both of above component is rendered inside index.tsx.
How can I manage global state from all the components including index.tsx , <TodoForm /> , <TodoListLineItem />. Here...
<TodoForm /> , is used to add to tasks to list.
<TodoListLineItem />, is used to display all added tasks from TodoForm component. when user hover over to each todo list item then user can able to remove perticular tasks-item from global management state.
Which one is best and reusable way to implement this global management state feature?
How one component changed state from A to B is reflected on related component by just manipulating global state object of application. If I put useState([]) into index.tsx then it will works well, But I want to manage state from TodoState.ts file. Thank You.
export default todoState;
Finally , I found and learned New concepts for React-Context API. You can checkout here StackBlitz Link
To manage global states React provides context-api. Use only when you have multiple level of component properties pass down in component tree from Top to bottom. I used very small example to understand context api for my different use-case.
First of all we need to use two context..
createContext [ used to create global state context ]
useContext [ used to get states from context from child component ].
To work with Context I created one <context.Provider> component. and all state management tasks are done with only this component level only. all child component just send events of what to do. and global context of provider component changes accordingly.
firstly, Create context..
export interface ItodoContext{
todoState? : Itodo[];
addNewTodoState?: (state?: string) => void;
removeTodoItemByIndex? : (index?: number) => void;
}
export const todoContext = createContext<ItodoContext[]>([{}]);
As, I am using React-Typescript functional component, as per Interface of context i defined all tasks of states. I passed all TodoState, function to manipulate TodoState like addNewTodoState, removeTodoItemByIndex.
then create Provider of context..
const allTodoStates = {
todoState,
addNewTodoState,
removeTodoItemByIndex
}
return(
<todoContext.Provider value = { [allTodoStates]}>
{props.children}
</todoContext.Provider>
)
Then I set Provider as parent component in tree in index.tsx component like this..
const App: FC = () => {
return (
<div className="h-100 w-100">
<TodoStateProvider>
<Navbar />
<div className="container">
<TodoForm />
<TodoListLineItem />
</div>
</TodoStateProvider>
</div>
);
}
See above all components now child of <TodoStateProvider> parent component.
When I need to add new state to context is inside <TodoForm> and how we can add state is as below code...
const [{addNewTodoState}] = useContext(todoContext);
const sendTodoItem = (e) => {
addNewTodoState(todoInput.trim());
}
and so on.. provider component has value property, and we can get those properties from child using useContext() hook. as we used above. See full working demo I have attached in above StackBlitz Link.
I am talking about a big web app that has jquery and bootstrap stuff init.
Part of rewriting this giant app using react and material UI, we are writing component by component. Things work fine in general as we make progress toward making this a react app soon.
Our problem:
When a new react component is loaded into the page, the existing (already loaded) react components will lose some or all styles.
We checked the new component load new style (classes) which are matching the names of existing classes for other already loaded components.
Ex:
As you can see, jss1, jss2, ... MuiCardHeader, MuiGrid, ... were also the names for the previously loaded components and now they are overwritten for the newly loaded component.
Packages.json:
webpack config:
Some component code: we are using make style and in some cases withstyle
Tried too much stuff. But nothing seems to work. On initial load, the map has all the correct material-ui stuff but as soon as I click on a marker and the popup component loads in. Now the map is messed up as some styles are overwritten.
How can we make it so that each component styles are named unique and never conflicts with other stuff?
I checked MUI docs and GitHub issues about kinda similar issue but nothing is working for us.
Any thoughts?
If I add:
import { StylesProvider, createGenerateClassName } from '#material-ui/core/styles';
const generateClassName1 = createGenerateClassName({
seed: 'App2',
});
my custom classes ( like root, mydivstyle) will have the prefix like app2-jss1-root, app2-jss2-mydivstyle, ...
but muiCard, MuiCardHeader, ... still being overwritten.
So after a few trial and error. I was able to solve this.
Basically we don't have a component tree path where you can could add a single class generator because of our app structure at this stage. We will soon have one.
The solution was to wrap every component like.
import { StylesProvider, createGenerateClassName } from '#material-ui/core/styles';
const generateClassName = createGenerateClassName({
seed: 'anyprefix',
});
class ActivityContainer extends Component {
render() {
return (
<StylesProvider generateClassName={generateClassName}>
<componenet/>
</StylesProvider>
);
};
}
I had to do this on the container level, this way any component loaded in that container will inherit this prefix.
No more conflicting class names between components and can load them dynamically.
Not a great way but no other option at least in our case. It will leave more classes on the DOM.
I'm working on a custom component in reactjs.
I want to add a feature to export component as an image and PDF.
Is it correct to use dom-to-image module in react? because it working with real DOM and react working with virtual DOM and i don't know maybe there are some conflicts or some performance issues.
if it's wrong please give me solution.
You can use refs to refer to react dom element and then parse the dom element to dom-to-html functions
Example :
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
And to access the element
JS way : let node = document.getElementByID('some-id')
React way : let node = this.myRef.current
Now pass node to dom-to-image functions like in its documentations.
PS : Set the ref to some state/store variable to access it anywhere in application.
React does eventually render into the regular DOM as regular DOM elements. There may be a react specific way to do this but dom-to-image should work.
What is alternative way of using package 'react-meteor-data' ? I'm using ES6 for writing react component. What would be best approach for writing meteor subscription in react component so that it will re-render the component if anything change on the server side.
What would be best approach for writing meteor subscription in react
component so that it will re-render the component if anything change
on the server side.
The best approach is using react-meteor-data. What is wrong with this package, that makes you think to not use it?
It even allows you to separate / decouple React Components from Meteor. This is really great because when you reach the point of having written some components that you want to reuse in another non-Meteor project you are free to go without greater hassle.
Of course you could write your own subscription container for react, but with this package you have all important stuff you need plus it is maintained and tested.
If you have trouble setting up a container for subscriptions, you may dig deeper into these tutorials:
https://guide.meteor.com/react.html
https://themeteorchef.com/tutorials/using-create-container
Using react-meteor-data, you first create a HOC container that subscribes to the data and passes it down as props to your component.
Container:
import { createContainer } from 'meteor/react-meteor-data';
export default FooContainer = createContainer(() => {
// Do all your reactive data access in this method.
// Note that this subscription will get cleaned up when your component is unmounted
var handle = Meteor.subscribe("todoList", this.props.id);
return {
currentUser: Meteor.user(),
listLoading: ! handle.ready(),
tasks: Tasks.find({listId: this.props.id}).fetch(),
};
}, Foo);
Component:
import FooContainer from './FooContainer';
class App extends React.Component {
render() {
return (
<div>
{this.props.currentUser.name}
</div>
)
}
}
export default FooContainer(App);
Check out React docs for Higher Order Components to understand how the container works.
We have a Webpack bundle exposing React components. The exposed components contain nested components from the same bundle.
We want to allow users to replace components with their own specific version.
For example, the following component structure;
class A extends React.Component {
render() {
return (
<B/>
);
}
}
const C = require('./C');
class B extends React.Component {
render() {
return (
<C/>
);
}
}
from which the top-level component A is exposed in the Webpack bundle:
const A = bundle.components.A;
Our server-side web framework relies on the exposed bundle interface to invoke the React components.
From this structure, an example use-case would be to replace the nested component C from component A.
Current options that we see for this are;
add a method to the class B (and A) to replace component C
create a registration mechanism, e.g. by using the filename or logical name of C, and a generic method to the bundle to replace a component. For example: bundle.component.replace('./C', './custom-C');
...
What would be the best way, i.e. common practice, to replace a (nested) React component in a Webpack bundle?
Joost, I've got the same problem and the way that I'm been handling this is creating an Block component which decides what component should take place.
This is a working project importing webpack bundles and deciding which one should take place. If they are defined in the template scope I switch the render method.
https://github.com/wallynm/react-template-system
In the end we chose to use render-props, HOCs, and adding some replace functions for specific components.