Manually update DraftJs ContentState with clicked text - reactjs

How can I manually update DraftJs's ContentState in response to clicked text?
I have a list of text item. When one is clicked I am passing that text down to Draftjs, but because I am setting the state using componentWillReceiveProps() it requires that I click the text twice to get an update.
componentWillReceiveProps() {
const activeNoteText = this.props.activeNoteText;
if (activeNoteText !== '') {
this.setState({ editorState: EditorState.createWithContent(ContentState.createFromText(activeNoteText)) });
}
}
First click: Update the App state and pass props down to Draftjs (component updates before receiving new props)
Second click: Now the prop is properly set and Draftjs updates (component updates with the props received on the first click)
How can I accomplish this in one pass? I know there's no componentDidReceiveProps and I know there's a good reason, though I can't claim to fully understand yet, so what's the best practices way to accomplish something like this?

Why are you using componentwillReceiveProps?.
What you can do, is have the states your setting in Draftjs i.e. editorState(Well, that's what I can make out) in its parent and whenever a list item is clicked on the click handler for that update the editorState and then pass it as props to Draft js.
Further for the condition, where you are checking if it is not empty,
You could use the
getInitialState(){
.....
}
For initialization when your component is initially loaded. So you could have a default value for editorState.

Related

Office UI Fabric React - Dropdown not respecting selectedKey prop

I have this code:
<Dropdown
selectedKey={someKeyInState}
onChange={(e,option) => {
// check if the dropdown should be updated
if(someCondition){
// update selected key
}
else {
// don't update selected key
}
}}
options={someOptions}
/>
I want to block updating the selected key if a certain condition is met.
But, Dropdown visually shows the option that I clicked on as selected.
How do I prevent this behavior?
If you are using react, you should not do in this way. Use a global state optionState and try to use conditional checks which state should be shown to use onChange method is triggered. In order to do this. First extract your conditional check to separate function.
myFunction = () => {
// do conditional check and setState for optionState
}
--------------------------
onChange={myFunction}
Then when you select pop the key and value from the option state and update to the selectedState, now react automatically update the state and UI
The problem was my state for selectedKey was undefined it nothing is selected. When you pass in undefined you're basically saying to fabric to control the selectedKey state on it's own. I fixed by passing null instead of undefined. That made the Dropdown fully controlled.

React pass an event into child component

I'm trying to find a way to pass event to child component in react.
I have something like that:
class ParentComponent extends Component<IProps, IState> {
render() {
return (
<div className={"ParentComponent"} onClick={this.onPageClick}>
... some navbar ...
... some `tabs` component
...
<ChildComponent/>
<AnotherChildComponent/>
...
... some footer ...
</div>
)
}
}
the child components are actually sub pages (changed using the tabs) with lot of logic and data inside them. (so I prefer manage them in separate components rather then one giant page).
some of the inner component have Editable labels which changed into an input (or in other case to a textarea or to MD editor) when the label is clicked.
there is an inner state in the child components when the user enter
into "Edit Mode" of the label. every component can have several of
this editable-labels.
The product request is when the user is clicking anywhere in the page the labels should exit from edit mode, so I need to capture the onClick on the master div like in the example and pass somehow the event into a function into the active child component so it will update it's inner state to exit edit-mode (if any).
Now, the solution I thought is to create a state variable in the parent which will be changed by the onPageClick function and pass into the child components
so they could update the local state. and then reset it on the parent again.
something like:
onPageClick() {
this.setState({ pageClicked: true }, () => {
this.setState({ pageClicked: false }
});
}
...
<ChildComponent pageClicked={this.state.pageClicked}/>
But it will change the parent state twice per click (and thus also the child state) even if not neccesary. the ideal why if I'll find a way to pass some event delegate to the children so a function will be triggered only inside the child when the parent onClick is triggered without any state changes in the parent.
Doe's it possible? do anyone have an idea how to implement something like that?
You are making your problem way more complicated than it needs to be.
You shouldn't listen for clicks on the outside component.
Instead, you should use your text input's onBlur event.
onBlur event is fired whenever a text input loses focus.

How to make animation on each rerender? (when new props come)

I have a react component which has props coming from the redux store. I need to do animation for icon from this component each time when I got new props. I change state when my component gets props on componentWillUpdate(). In this way I can get animation but just the first time, then I already have this class in DOM element and new update doesn't call animation. How I see I have to delete class which provides animation from DOM, but I am not sure when to do it. I don't buttons, I have just props comes and each time when it happens I need the animation. I read that there is a way with refs, but I don't know how to use refs in such situation
Let us assume that the animation which is triggered on receipt of new props is a bounce animation, which is triggered once a bounce-class class is appended to the desired HTML element.
Instead of componentWillUpdate, I utilise the componentDidUpdate life cycle method, since I wish to call a setState when the required prop is updated. It takes the previous props and the previous state. Let us assume, that the prop which we are watching for changes is bounceProp.
componentDidUpdate(prevProps, prevState) {
if (prevProps.bounceProp !== this.props.bounceProp) {
this.setState({ shouldBounce: true });
}
}
React relies on Synthetic Events, which also includes animation-events. We use the onAnimationEnd event on the desired element, to make shouldBounce: false.
<div
className={
this.state.shouldBounce ? "bounce-class other-class" : "other-class"
}
onAnimationEnd={() => this.setState({ shouldBounce: false })}
/>;
Here the bounce-class class which is responsible for the animation, automatically removes and applies itself based on the shouldBounce variable.

With ReactJS Popup, how can I make it only show one pop up at a time?

I am experimenting with different React popup libraries. I found reactjs-popup and began playing with the codesandbox. I created a fork of the environment here https://codesandbox.io/s/pp60zjkxlj
When I click the first (or second) button, it displays the corresponding popup. What i'd like is so that when I click other button, it will display that button's popup and hide any other popups that are visible. The goal is that only one popup should be visible on screen at any time.
Is this possible with this library?
See https://codesandbox.io/s/pp60zjkxlj
have a common state for popup when first button is clicked set the state to first button and based on the state
I would look into Portals where you can use a portal that sits outside of the jsx that wishes to use it.
imo it is the best way to implement a modal and i believe there's not to much need to add another dependency to your project and just create one this way that matches your needs.
You will need to pass props into the Popup to tell it when to open and when not to open.
Your component should have state set for each popover or be passed in props to tell the Popovers when to display. You can set in a constructor a default state and spread those before setting the new state with the new Popover open. This is how I handle modals.
constructor(props) {
super(props);
this.state = {
vendor: {} // Just showing my default state this gets set and this.defaultState is spread after my fetch request completes in componentWillMount()
};
this.defaultState = {
isPopoverOpen: {
// ---- Default Popover booleans can go here
editVendor: false
}
};
}
Actual function that controls the Popover status in the state.
// onClick of element would be onClick={this.handleTogglePopover('editVendor')}
handleTogglePopover = id => {
const currentState = Object.assign({}, this.state);
this.setState({
currentState,
...this.defaultState, // spreading default will set everything to false
isPopoverOpen: {
[id]: true // then the newly clicked to true
}
});
};

reactjs componentWillMount not calling every time when i open modal

i am displaying table data inside modal dialog, when i click table row to edit data it will open another modal dialog, here i am getting row data by using clicked row id inside componentWillMount(). but when i close edit modal dialog and try to edit other table row componentWillMount() will not called. so edit modal dialog is empty. why componentWillMount not calling every time?
As Nir H already mentioned, Dialog component mounts into the dom only once, and then after you close it, becomes invisible (by changing the left position to -10000px) but still present inside the DOM.
So its clearly that componentWillMount and componentDidMount methods will be called only once. If you want to open Dialog component with different options every time, you can do the folloving:
Save ref to the Dialog component instanse in the parent component:
ref={instance => {this.RowDialog = instance}}
Then you can open Dialog by using it handleOpen method:
onRowClick = (event) => {
this.RowDialog.handleOpen();
}
I used following steps to fix it.
i used {(this.state.open) ? <Dialog open={true} ></Dialog> : null
second step by unmounting the component componentWillUnmount() { }

Resources