inconsistent state and display in React when using browser 'back' button - reactjs

I am using React 16.1.1 (with the react-rails gem) in a Rails 5.1 app.
The React components on a specific page work fine, except when going back to this page with the browser 'back' button (tested with firefox / chrome / safari). In that case, the display is inconsistent with the state of the component. I've setup a demo of the problem: https://lit-bastion-28654.herokuapp.com/.
Steps to reproduce:
be on /page1
click the 'selection mode' button, it sets 'selectionMode' to true
click 'page 2'
use 'back' button to go back to page 1
EXPECTED BEHAVIOUR: the button is grey (selectionMode is reset to false when component loaded). OBSERVED BEHAVIOUR: the button is still blue?!
There, you can see that the button is blue, as if selectionMode was true, but the react browser plugin shows that selectionMode is false. The React browser plugin shows false information: it shows that the button does not have the 'btn-primary' class (which is normal if selectionMode is false), but you can obviously see that in the DOM, it has the 'btn-primary' class, since it is appears blue.
This is my code:
page1.html.erb:
<%= react_component("EditableCardList", { editable: true }) %>
editable_card_list.js.jsx:
class EditableCardList extends React.Component {
constructor(props) {
super(props);
this.state = {
selectionMode: false
};
this.toggleSelectionMode = this.toggleSelectionMode.bind(this);
}
toggleSelectionMode() {
this.setState(prevState => ({ selectionMode: !prevState.selectionMode }));
}
render() {
if (this.props.editable === true)
return (
<div>
<div className="row card-buttons">
<div className="col-md-12">
<div className="pull-left">
<ManageCardsButtons
selectionMode={this.state.selectionMode}
toggleSelectionMode={this.toggleSelectionMode}
/>
</div>
</div>
</div>
</div>
)
}
}
manage_cards_buttons.js.jsx:
class ManageCardsButtons extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<span>
<button type="button" className={`btn btn-default btn-sm ${this.props.selectionMode ? 'btn-primary' : ''}`} onClick={this.props.toggleSelectionMode}>Selection mode</button>
{ this.props.selectionMode && <span>selection mode</span> }
</span>
)
}
}
So my question is: How to make sure that, after using 'back' in the browser, the button is rerendered properly (and appears grey instead of blue)?
The issue may be related with turbolinks and caching, but I've not been able to figure it out yet.

React and TurboLinks conflict, so my final solution was to disable TurboLinks caching on that specific page.

When you go back to page1, Component rerenders, and sets the default selectionMode which is false in your case.
you can use redux.
you can save selectionMode to your
localStorage when it changes, and by default load it from the
storage.

Related

All buttons close on click of one button

please i am building a FAQs page and i made a series of buttons which when clicked displays a hidden paragraph underneath each button, now the issue is all buttons respond to one button being clicked on and they all display their respective paragraphs, i want each button to display it's own hidden paragraph alone.
this is the react code i used
class FAQ extends React.Component {
constructor () {
super()
this.state = {
isHidden: true,
}
}
toggleHidden () {
this.setState({
isHidden: !this.state.isHidden})
}
<div className="faq--button">
<button onClick={this.toggleHidden.bind(this)}>button to click</button>
{!this.state.isHidden && <p>lorem ipsum"</p>}
</div>
Currently isHidden is used for all buttons, which will have the same effect in each button. So you need to add separate states for each button. Like isHidden2, isHidden3....

getting the state of navbar in bootstrap 4 using React js

I'm trying to toggle some styling depending on whether the navbar is opened or closed (in mobile and tablet views), I have seen solutions for jQuery but i want to do it in react js.
i have tried setting a state on the hamburger button and toggling it on user interaction but it's really not a good solution and it's flawed since sometimes the user can close the navbar without clicking the hamburger button, instead i want to get the actual state of the navbar
is this possible in react js? if so how?
Use a boolean state variable and toggle it when the Hamburger is clicked...
...
constructor(props) {
super(props);
this.state = { showNav: true };
this.toggleNav = this.toggleNav.bind(this);
}
toggleNav() {
this.setState({
showNav: !this.state.showNav
})
}
In the Navbar markup...
<nav>
<button className="navbar-toggler" type="button" onClick={this.toggleNav}>
<span className="navbar-toggler-icon"></span>
</button>
<div className={(showNav ? 'show' : '') + ' collapse navbar-collapse'}>
</div>
</nav>
Demo: https://codeply.com/p/z0rSHluhPi

I have to show a pop on click of a span but elements not appearing in the DOM

I am trying to display a div pop up on click of a span. Even though the code inside the function is executing, the div is not at all visible in the DOM.
Am not sure where I am going wrong.
<span id="test" onClick={()=>this.bindPopUpData("test")}>
Here I am calling the function to bind popup.
bindPopUpData=(dimension) =>{
return (
<div id="">
<div className="details_table">
<div className="close_popup">
<span className="icon-Close"></span>
</div>
</div>
</div>
);
}
-- Here I am trying to bind that popup
Can someone please tell where I am going wrong?
The issue is that your event handler is just returning a value, you're not telling the browser to put it anywhere.
Option 1: build the popup into the DOM with display:none and use your event handler to show/hide it.
Option 2: make your event handler inject the popup into the DOM with document.createElement and document.appendChild functionalities.
With React I'd recommend option 1 because you can make the popup a component and only render it if the parent component detects the event.
class myComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
showpopup: false
}
this.myHandler = this.myHandler.bind(this)
}
myHandler () {
this.setState({showpopup: !showpopup})
}
render () {
return (
<section>
<span onClick={this.myHandler}></span>
{this.state.showpopup ? <Popup /> : ''}
</section>
)}
}

Cannot read property 'show' of undefined React js

I'm using SkyLight react component to make modal dialog. The problem that I'm trying to solve is how to show different content in modal dialog using only one button.
<a className="btn btn-secondary" onClick={() => {
this.setState({
features: plan.features
})
this.dialog.show()
}}>Features</a>
The content that I want to show is Array.
For example: features:["Feature 1", "Feature 2"]
I'm keeping that features in state an show them on click using map looping.
<SkyLight hideOnOverlayClicked ref={ref => this.dialog = ref} title="Hi, I'm a simple modal">
{
this.state.features.map((feature)=>{
<h4>{feature}</h4>
})
}
</SkyLight>
When I click that button I have this error: Cannot read property 'show' of undefined
Any ideas how to solve this?\
Thanks
The most probably is that you are missing the ref Creation on your constructor.
class ParentComponentForModal extends Component{
constructor(){
// rest of your constructor.
this.dialog = React.createRef();
}
//....rest of your code
}
and then change your component to have ref={this.dialog} instead of ref={ref => this.dialog = ref}
<SkyLight hideOnOverlayClicked ref={this.dialog} .....
adding a working sample on codesandbox

Ckeditor disable auto inline won't disable inline from being selected on page load

I'm trying to develop a simple CMS for my page. I want it to where I can edit and delete a users reply on click of a button. I got the delete functionality done so I figured for the reply functionality I would use CKeditor. What I'm struggling with is not being able to disable the autoinline feature. I can still select my div on load of the page rather than clicking a button to enable the inline feature but I don't know what I am doing wrong?
I have tried setting the feature directly in my index.html file, a custom js script file and the config.js ckeditor file but none worked. I am using Ckeditor 4.
this is the snippit of code I'm trying to use to disable inline on my div element but it's not working and I don't know why, i currently have it placed in a custom.js script file and I'm calling it from my index.html file
CKEDITOR.disableAutoInline = true;
Here is my code for my replies page:
import React from 'react';
import CKEditor from 'react-ckeditor-component';
import ForumpageService from '../../services/forumService';
import appController from '../../controllers/appController';
class Forumreplies extends React.Component {
constructor(props){
super(props);
this.elementName = "editor_" + this.props.id;
this.editReply = this.editReply.bind(this);
this.state = {
reply: '',
errorMsg: '',
isLoggedin: false,
// Ck Editor State
reply: '',
}
}
async componentDidMount(){
const topicId = this.props.match.params.topicid
const postDetails = await ForumpageService.replyDetails({topicId: topicId})
this.setState({
postDetails: postDetails[0],
topicId: topicId
})
await this.postReplies();
}
// Edit the reply
async editReply(id, e){
//CKEDITOR.inline(this.elementName);
}
async postReplies(){
const repliesData = await ForumpageService.postreplyDetails({topicId: this.state.topicId})
await this.setState({repliesData});
}
render(){
const repliesData = currentReply.map((row, index) => {
return (
<div className="row" id="reply-messages" key={index}>
<div className="col-md-8" suppressContentEditableWarning contentEditable="true" id={this.elementName}>
<p dangerouslySetInnerHTML={{__html: row.reply_message }} />
</div>
<div className="col-md-2">
{this.state.isloggedinuserId == row.reply_user_id && this.state.isLoggedin == true ? <i className="far fa-edit" onClick={this.editReply.bind(this, row.reply_id)} title="Edit this reply?"></i> : null }
</div>
</div>
})
return (
<div className="container" id="forum-replies">
<div className="row">
{repliesData}
</div>
</div>
)
}
}
export default Forumreplies;
Instead of creating a div and calling CKEDITOR.inline, you should try to use the react-ckeditor-component as its own way (not as an inline editor).
You could do something like: if the button wasn't pressed, render a div with the text content, but after the button was pressed, render a <CKEditor /> component as in the documentation
There is no documented way to set the editor as inline in this package that you are using.
EDIT:
I can see you are not using the react-ckeditor-component features, but following what you've done so far, you could set the contentEditable="true" property of the div only when the button is pressed:
<div className="col-md-8" suppressContentEditableWarning contentEditable={this.state.isEditing} id={this.elementName}>
<p dangerouslySetInnerHTML={{__html: row.reply_message }} />
</div>
And then set the isEditing to true on the onClick handler. Your component will update and then re-render with the contentEditable property set to true

Resources