Advice on Component react-ratings-declaritive - reactjs

I am using a component which I have downloaded from below:
https://www.npmjs.com/package/react-ratings-declarative
It works great, but I really need the functionality to disable the component in instances where I just want to display the rating, but not have the interactive element.
I have looked through the documentation and can't find anything to disable it directly. I can see some stuff on disabling inline styles, but not sure how this would work.
I have copied the raw HTML and tried to reconstruct a component with this functionality, but there seems to be so many styles to copy, I don't think this approach would work.
Can anyone advise if this is possible or recommend an alternative component which does this?

Just don't call the method that sets state. I used the example and got rid of the changeRating method and deleted the changeRating attribute. If there is no way to change the state, users can't update the ratings.
//IMPORT STATEMENTS ETC...
class Foo extends React.Component {
constructor(props) {
super(props)
this.state = { rating: 5 }
}
/* YOU DON'T NEED THIS METHOD EITHER IF YOU'RE NOT CHANGING STATE
changeRating(rating) {
this.setState({
rating: rating
})
}
*/
render() {
return (
<div>
<Ratings
/*changeRating={this.changeRating} <-- GET RID OF THIS LINE*/
rating={this.state.rating}
widgetRatedColors='blue'>
<Ratings.Widget />
<Ratings.Widget />
<Ratings.Widget
widgetDimension='60px'
svgIconViewBox='0 0 5 5'
svgIconPath='M2 1 h1 v1 h1 v1 h-1 v1 h-1 v-1 h-1 v-1 h1 z'
/>
<Ratings.Widget widgetHoverColor='black' />
<Ratings.Widget />
</Ratings>
</div>
)
}
}
function App() {
return (
<div className='App'>
<main>
<Foo />
</main>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('example'))

Related

Is it possible to render a react class when given its name as a string?

Here's a smaller example of what I'm trying to do, I don't know if it's possible to do something similar or I should use an entirely different method.
import {Design1, Design2} from './page-designs';
let designs = {
"page1":"Design1",
"page2":"Design2",
"page3":"Design1",
"page4":"Design2"
}
class DesignedPage extends React.Component {
let Design = designs[this.props.page]
render(){
return(
<div className="row flex-fill d-flex">
<div className="col-1"></div>
<Design /* This is the line that fails */
data = {this.props.data}
/>
</div>
</div>
)}
}
class Main extends React.Component {
render(){
return(
<DesignedPage
page = {this.props.openPage} /*this could be any of page1-4 depending on button a click*/
data = {this.props.data}
/>
)}
}
Ideally this would render the react elements Design1 or Design2 based on what props.page is passed, but instead it returns
"Warning: <Design1 /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements." and "The tag <Design1> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter."
I've thought of making a long if, elseif, elseif.. statement in DesignedPage (the actual code has many more than 2 designs), which I'm fairly confident would work, but looks very messy in comparison.
You can't render the component name by getting its name as a string. You need to map the string to the component iteself:
let designs = {
"page1":Design1,
"page2":Design2,
}
If you pass a string, react would think it's a HTML tag, hence it say'Design1' tag is unrecognised. Also, you could import the components and use them as values in the designs object in place of strings.
let designs = {
"page1":Design1,
"page2":Design2,
"page3":Design1,
"page4":Design2
}
make one function that return react component..
getComponent = ({data, pageName}) => {
if(pageName === "page1") return <Desig1 />;
if(pageName === "page2") return <Design2 />;
}
and call function from render of DesignedPage component
const {page, data} = this.props;
return(
<div className="row flex-fill d-flex">
<div className="col-1">
{getComponent(page, data)}
</div>
</div>
)

React - Carbon Design System - Transition in right sidebar not working

I'm trying to use Carbon Design System for a project, and I need some help with the UI Shell.
The transition of the right sidebar is not working properly.
Here is the working example, see how smooth it opens and closes (see live example):
Here is the example with issues. There's no transition (see live example):
I think it's related to how High Order Components work. Here's my theory:
HeaderPanel is being rendered inside the HeaderContainer, which is a High Order Component.
When the state variable switchCollapsed changes, the HeaderContainer is rendered entirely again.
So this would explain why there's no transition.
I'm new to React, and this theory is based on my React knowledge until now. Please correct me if I'm wrong
Here's a piece of the code of the second example (simplified for the brevity of this post). See the entire code here
class App extends React.Component {
constructor(props) {
super(props);
this.toggleSwitch = this.toggleSwitch.bind(this);
this.state = { switchCollapsed: true };
}
toggleSwitch() {
this.setState(state => ({
switchCollapsed: !state.switchCollapsed
}));
}
render() {
return (
<div className="container">
<HeaderContainer
render={({ isSideNavExpanded, onClickSideNavExpand }) => (
<>
<Header aria-label="IBM Platform Name">
<HeaderMenuButton
onClick={onClickSideNavExpand}
isActive={isSideNavExpanded}
/>
<HeaderGlobalBar>
<HeaderGlobalAction onClick={this.toggleSwitch}>
<UserAvatar20 />
</HeaderGlobalAction>
</HeaderGlobalBar>
<HeaderPanel
aria-label="Header Panel"
expanded={!this.state.switchCollapsed}
/>
<SideNav
aria-label="Side navigation"
expanded={isSideNavExpanded}
>
<SideNavItems>
</SideNavItems>
</SideNav>
</Header>
<StoryContent />
</>
)}
/>
</div>
);
}
}
render(<App />, document.getElementById("root"));
Moreover, if I change the property on React Dev Tools, the transition work!

Issue refreshing child components in React after implementing React DnD

I'm trying to implement a sortable list of sortable lists in React, using React DnD. Prior to implementing the drag and drop side of things, all was working well.
I have a container component, which renders this:
<DndProvider backend={Backend}>
{this.state.classifications.map((classification, index) =>
<Classification id={classification.id} classification={classification} reportTemplate={this} key={classification.id} index={index} />
)}
</DndProvider>
The Classification extends Component, constructed like this:
constructor(props) {
super(props);
this.state = {
isEditing: false,
classification: props.classification
};
}
... and renders this (condensed for brevity):
<div className="panel-body">
<DndProvider backend={Backend}>
{this.state.classification.labels.map((label, index) =>
<Label id={label.id} label={label} reportTemplate={this.props.reportTemplate} key={label.id} index={index} />
)}
</DndProvider>
</div>
In turn, the Label also extends component, constructed like this:
constructor(props) {
super(props);
this.state = {
isEditing: false,
label: props.label
};
}
... and renders like this (again condensed for brevity):
return (
<div className={"panel panel-default panel-label " + (isDragging ? "dragging " : "") + (isOver ? " over" : "")}>
<div className="panel-heading" role="tab" id={"label-" + this.state.label.id}>
<div className="panel-title">
<div className="row">
<div className="col-xs-6 label-details">
{this.state.isEditing
? <input type="text" className="form-control" value={this.state.label.value} onChange={e => this.props.reportTemplate.onLabelValueChange(e, this.state.label.classificationId, this.state.label.id, 'value')} />
: <p className="form-control-static">{this.state.label.value}</p>
}
<div className="subuser-container">...</div>
</div>
</div>
</div>
</div>
);
All of this works well - when the user makes a change from the Label child component, it gets updated in the root component and everything syncs up and refreshes.
However, when implementing React DnD, both the Classification and Label components have been wrapped in Drag and Drop decorators, to provide sorting. The sorting via drag and drop works perfectly. However: this has caused the updating of elements to stop working (i.e., when a change is made from the Label, the update is fed through to the root Component correctly, but it doesn't then refresh down the tree).
Both the classification and label dnd implementations are like this in the render method:
return connectDropTarget(connectDragSource(...));
... and this when exporting the component:
export default DropTarget('classification', classificationTarget, classificationDropCollect)(DragSource('classification', classificationSource, classificationDragCollect)(Classification));
Interestingly, when a label is edited, the refresh does then occur when the user drags and drops the component. So its like the drag and drop will trigger a component refresh, but not the other onChange functions.
That was a long question, apologies. I'm almost certain someone else will have experienced this issue, so any pointers gratefully appreciated.
Ok so i've basically answered my own question, but many thanks to those who posted comments on here to help narrow it down.
The answer was that my state object is complex and deep, and the component/decorator implementation of React DnD seems to have an issue with that. My assumption is that there is some behaviour in the decorator's shouldComponentUpdate that is blocking the components refresh when a deep property is update. React DnD's own documentation refers to the decorators as "legacy", which is fair enough.
I updated our components to use hooks instead of decorators, and it all sprang to life. So the answer is this, if your DnD implementation is deep and complex, use hooks.
Here is an example of your code without DnD that won't work either because the prop is copied to state in the constructor and on concurrent renders the prop is never used again, only the state.
In Child you can see that it will render but counter never changes, in CorrectChild the counter will change because it's just using props.counter.
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {//copied only once in constructor
counterFromParent: props.counter,
};
}
rendered=0;
render() {
this.rendered++;
return (
<div>
<h3>in broken Child rendered {this.rendered} times</h3>
<button onClick={this.props.up}>UP</button>
<pre>
{JSON.stringify(this.state, undefined, 2)}
</pre>
</div>
);
}
}
class CorrectChild extends React.Component {
render() {
//not copying props.count, just using it
return (
<div>
<h3>in correct Child</h3>
<button onClick={this.props.up}>UP</button>
<pre>
{JSON.stringify(this.props, undefined, 2)}
</pre>
</div>
);
}
}
function App() {
const [state, setState] = React.useState({ counter: 1 });
const up = React.useCallback(
() =>
setState((state) => ({
...state,
counter: state.counter + 1,
})),
[]
);
return (
<div>
<h3>state in App:</h3>
<pre>{JSON.stringify(state, undefined, 2)}</pre>
<Child counter={state.counter} up={up} />
<CorrectChild counter={state.counter} up={up} />
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
If you still experience that without DnD your code "works" then please provide a Minimal, Reproducible Example of it "not working".

How to hide / show the content of a component that is reused by different views in ReactJS

I have two views that call a particular component and this makes it difficult for me to hide / show when the component is needed. In this way, I have the following:
I tried to make a display: none to overide the styles but it is a problem. This is because the views when using the same component, the classes of the CSS are called the same and when I make the display: none, I get it not to show in "News" but in "Home" it also affects and it is not shown to me.
I tried it:
Component Section:
<div className="section_news">
{orden.map(this.renderSection)}
<ViewAllNews mostrarCategorias={false} categoriaId={newsId} />
If I remove the title like this, I'll leave the view "Home" and "News", and that's not what I intend to do.
Next, I leave the original piece of code:
View named "Home":
<div className="contentbar">
<Section title="Ult. News" />
<Section
notices_id={19}
orden={[[0, 3], [3, 1], [4, 2]]}
/>
</div>
**View named "News": **
<Section
notices_id={data.post.category.id}
orden={[[0, 2], [2, 3]]}
/>
Component Section:
<div className="section_news">
<Titles title={title || (category && category.title)} />
{orden.map(this.renderSection)}
<ViewAllNews categoriaId={newsId} />
Component ViewAllNews:
return (
<Link to={`/news/c/${categoryId}/`}>
<div className="parentLineViewAll">
<div className="LineViewAll" />
<div className="line" />
<div className="Views">View All</div>
<div className="arrowMore">
<FontAwesomeIcon icon="chevron-circle-right" />
</div>
</div>
</Link>
);
};
As you can see, the view of "Home" and "Views" make use of the same component.
What I really need is to hide the component named for the "News" view and also hide the "ViewAllNews" component only for the "News" view.
Thanks for your help!
The easiest way to hide / show react components is to use conditional rendering
Here is a basic example:
class MyComponent Extends React.Component {
constructor(props){
super(props)
this.state = {
isVisible: false, // <-- add a value to state so we can track the components visibility
}
}
show = () => {
this.setState({ isVisible: false })
}
hide = () => {
this.setState({ isVisible: true })
}
render(){
if(this.state.isVisible){
return (
/* your component code */
)
}
}
}
If you want to toggle the component from inside a parent component then you can control this with a ref:
class Parent Extends React.Component {
constructor(props){
this.myRef = React.createRef()
}
render(){
return <MyComponent ref={this.myRef}>
}
}
Once the component mounts, you can check if the ref has been set and call the method anywhere in your code:
if(this.myRef.current){
this.myRef.current.show() // or .hide()
}
You can also control the components visibility via props:
function MyComponent({ isVisible }){
if(isVisible){
return (
/* your component code */
)
}
}
Hope that helps, let me know if you have any questions!
a way to implement this componentWillUnmount() and componentWillMount() ,
like to this example , hope help you this.

Update React component with placeholder replaced by another component

I have a react component rendered via:
render() {
var props = this.props,
config = props.config;
return(
<section className="prompt" data-component="prompt" style={{color: config.get('promptTextColor')}}>
<div className="prompt-text-1 emphasis-font-web-safe">
<DangerouslySetInnerHtml text={config.get('text1')} />
</div>
</section>
);
}
"text1" will be something like
<div><ctaPlaceholder></ctaPlaceholder></div>
and I want to replace that ctaPlaceholder with a different component (which is imported within the component I am rendering).
I have been able to replace just using normal javascript, basically just writing a replace function within componentDidMount, but would like to replace with the full component instead of just a string.
Thanks,
Update:
Eventually I have come up with putting this inside componentDidMount:
ReactDOM.render(<Provider store={store}>
<CTA className="myClass" url={this.props.config.get('ctaUrl')} style={{color: this.props.config.get('submitColor')}}>Foo</CTA>
</Provider>, document.getElementsByTagName('cta')[0]);
I need to import store and provider in the file for this, which I don't think is specially clean as I had it before just in one place in my solution. But unless someone can help me with a better solution is they only way I was able to make it work
The best way to do this would be to render the right component based on a prop or state, that's the react way.
I can't tell your specific use case, but the core for your use case will be something like this:
renderPlaceholder() {
if (this.state.isCtaPlaceholder) {
return <DangerouslySetInnerHtml text={config.get('text1')} />;
} else {
return <OtherComponent />
}
}
render() {
var props = this.props,
config = props.config;
return(
<section className="prompt" data-component="prompt" style={{color: config.get('promptTextColor')}}>
<div className="prompt-text-1 emphasis-font-web-safe">
{ this.renderPlaceholder() }
</div>
</section>
);
You just need to decide what to render based on state/props, when and the best to do i is always dependent on the specific use case.

Resources