I have the following problem: I'm working on a react app and I have a div, which contains multiple span-tags. The value of these span tags are dynamically changed and whenever a change of these values occured, I'd like to trigger an animation. While the values are changing without any problems, the animation only triggers during the first initial load. Afterward it fails to trigger. Is there any way I can tell or force my app to trigger the animation when the value of the div-container is changed?
Here is a shortened example of my code:
<div className="animation">
<span>{value}</span>
<span>{value2}</span>
</div>
I don't know how your values are structured but here's my recommendation
Make an animated span component and get the value as a prop.
Then whenever that value changes, The span component will re-render and you will see the animation.
Put your value and value2 in to the state, and then change the state value and your component will re-render.
Like this:
constructor() {
super();
this.state = {
value: 'animation',
value2: 'animation'
};
}
changeAnimation() {
this.setState({
value: 'animation2',
value2: 'animation2'
})
}
Related
I'm working with BootstrapVue to get this Accordian like component to work. Part of that entails setting the visibility of a particular item.
Ie,
const obj = {
someData: [...// properties here],
visible: false
}
And this gets fed down to an Accordian component like so:
<Accordian :visible.sync="obj.visible" />
And inside Accordian:
props: {
visible: {
type: Boolean
}
}
THEN... I need to attach it to a b-collapse html tag using v-model because that is how it is suggested on their site. But that throws me this very long list of 'don't modify props directly error'
<b-collapse v-model="visibile" />
Any idea what I am doing wrong?
EDIT: And an important part I forgot to mention, the error only occurs on initial page load. Afterwards the accordian's are fine to use and work (most of the time).
You can't use v-model with a prop because props are meant to be readonly.
Instead, bind <b-collapse>.visible to the visible prop, and emit the update:visible event with the event data whenever <b-collapse>.input event occurs. The update:visible event updates the parent's visible prop via the .sync modifier.
<b-collapse :visible="visible" #input="$emit('update:visible', $event)">
demo
Inside of my React application, I have the following JSX code:
import React, { Component } from 'react'
export default class CategoryForm extends Component {
render() {
return (
<div className="category-form">
<label>
Category
<select value={this.props.selectedCategory} id="selectedCategory" onChange={this.props.handleChange}>
<option value="Best">Best</option>
<option value="Controversial">Controversial</option>
<option value="Hot">Hot</option>
<option value="New">New</option>
<option value="Rising">Rising</option>
<option value="Top">Top</option>
</select>
</label>
</div>
)
}
}
It's a simple element with elements as children. The default value is initialized as, "Best". When the page is initially visited or refreshed, the value contained in the element reverts to "Best" (as expected), but when a user navigates away from the page and presses the back button, the element retains whatever value was previously selected. How do I prevent this behavior? I'm trying to avoid forcing a re-render.
EDIT: I made the mistake of omitting code because I thought it would make the question more simple. Here's the state that I'm initializing in the constructor of the component, as well as the child component being created in the parent component. I modified my code according to the React documentation (and HMR) on controlled components, and I am still having the same problem.
export default class App extends Component {
constructor(props) {
super(props)
this.state= {
selectedCategory: "Best",
minScore: -100,
numPosts: 25,
subreddit: "",
searchTerm: "",
timeframe: "hour",
postArray: [],
animationTracker: false,
selectedForm: "Category",
}
this.handleChange = this.handleChange.bind(this);
this.backendCall = this.backendCall.bind(this);
this.changeForm = this.changeForm.bind(this);
}
\\ handle change method
handleChange(event) {
// dynamically set the key of the setstate object to be equal to the id of the specific form
let selectedCategory = event.target.id;
this.setState({[selectedCategory]: event.target.value});
}
\\ later on...
{this.state.selectedForm === "Category"
? <CategoryForm selectedCategory={this.state.selectedCategory} handleChange={this.handleChange.bind(this)}/>
: <TermForm handleChange={this.handleChange.bind(this)}
searchTerm={this.state.searchTerm} timeframe={this.state.timeframe} />
}
ScreenshotHere is a screenshot showing the problem in action. After pressing the to back button, the state is reinitialized (which should change the value to "Best"), but the value of my element remains at whatever the user selected before navigating away from the page (in this case, "Hot"). In addition, if I modify the fields below (Minimum score and number of posts), then navigate away from the page, then press the back button, those fields follow the expected behavior and revert to the default state.
We might need to see more of your code.
I'm guessing that the handlechange() function sets the local state to the selected option. You'll need to clear that state to revert to the default option.
I have an input with the disabled boolean propagated from the props. I've found that with that disabled variable being set, even when it's true I cannot type into the input. I can, however, type into the input if I hold the mouse down on it and keep it down as I type.
This happens when I render the component as both controlled and uncontrolled.
The only way to fix it is to either removing disabled or setting disabled={false} -- but I need it to be variabled.
This is my input:
class DashboardWidgetTitle extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.state.title = props.widget.getTitle();
}
render () {
return <input className="title"
value={this.state.title}
disabled={!this.props.isEditMode}
onChange={this._onInputChange.bind(this)}/>
}
_onInputChange(e) {
logit("input change");
this.setState({title: e.target.value});
}
}
Thanks!
EDIT: Extra info --
This is used in a widget within an implementation of ReactGridLayout.
The component is rendered by a widget that is rendered by the implementation of react grid layout, the "dashboard". That Dashboard has isEditMode as a state that's changed externally via a toggle in Angular (we use React within Angular).
If I switch tabs and come back, the focus remains. Otherwise whenever I type a letter, the input becomes unfocused.
The input isn't disabled when it shouldn't be, it just has focusing issues -- however removing the disabled attribute or setting it as a static variable, the issue doesn't remain.
When I switch the disabled toggle to be isEditMode rather than !isEditMode, everything works. It seems to be there's an onclick on the draggable/resizable portion of the ReactGridLayout that's causing some issues.
My issue was described right here: https://github.com/STRML/react-grid-layout/issues/615
My own fault of poor research.
I have a modal with some input fields. I can easily pass the data automatically with the user typing an input, using onChange function in the input field, as
<Input onChange={this.props.store.handleCategoryChange} type="text" />
and .. (Using a mobx store, irellevant though)
#observable categoryValue;
#action handleCategoryChange = (e, data) => {
this.categoryValue = data.value;
e.preventDefault();
};
However, I want to add a function where the user can pre-fill this with information elsewhere in the application. I have the data to pre-fill the input fields with, but I can't figure out how do actually input it programatically, without the user doing it?
I need to invoke the above handleCategoryChange function. But my variable would be equal to data.value .. Which presents a problem! Invoking this function by myself isn't possible, because I won't have the event e nor a value called data.value as I will "just" pass in a variable by itself.
What's the right way to programatically fill an input field automatically in React, using variables elsewhere? I need to invoke the onChange function somehow, but the input values will be different..
Use controlled component for this situation, define a value property of input element like this:
<Input value={variable_name} ....
Whenever you will update that variable, automatically that value will get populated in input element.
Now you can populate some default value by assigning a value to variable_name and user can update that value by onChange function.
As per DOC:
An input form element whose value is controlled by React in this way
is called a "controlled component".
Pass in the value property for input:
<input type="text" value={this.state.value} onChange={(e) => {this.setState({value: e.target.value })}/>
you can use the controlled component and pass the value to it.
<input type="text" value{this.state.value}
onChange={()=> {this.setState({value:e.target.value })}}
Good question. I'm having the same issue, and just found a solution.
The problem is that:
You can't just use the default state of the modal component to set the initial input value, because the modal renders one time within the parent component (starting off invisible), so the default state of the Modal wont keep up with any changes to the 'pre-filled' info in the store that the inputs within the modal require access to.
You can't use the value attribute of the input to reference some redux store prop, since this is needed to reference the onChange function so the user can make changes to that pre-filled info.
And, you can't use the onChange function to set the initial value, because it is required to update the local state with the users changes - not set an initial value. Anyway, this requires the user to click on something, and you want the modal inputs to be pre-populated before the user does anything as soon as the modal opens...
So. What we need is to update these input fields every time the Modal attribute isModalOpen (or whatever you are using) changes.
(ie, pre-populate the fields when the Modal is opened).
Again, note that opening the Modal is not RENDERING the modal, it was already rendered, once, and has sat there being invisible until that isModalOpen attribute changed to true.
The Solution:
Step 1: make a handler function in the Modal component that prefills the inputdata by updating the local state of the Modal component. Mine looks like this :
handlePreFillModalInputsOnOpen = () => {
this.setState(() => ({
orthForm: this.props.matchLexUnit['orthForm'],
orthVar: this.props.matchLexUnit['orthVar'],
oldOrthForm: this.props.matchLexUnit['oldOrthForm'],
oldOrthVar: this.props.matchLexUnit['oldOrthVar'],
source: this.props.matchLexUnit['source'],
namedEntityCheck: this.props.matchLexUnit['namedEntityCheck'],
styleMarkingCheck: this.props.matchLexUnit['styleMarkingCheck'],
artificialCheck: this.props.matchLexUnit['artificialCheck'],
error: ''
}));
};
Step 2: Make that function fire ONLY when the isOpen attribute of the modal changes from false to true.
(This is the meat of your problem I think).
Use the lifecycle method componentDidUpdate. This will execute every time the props of the modal change.
componentDidUpdate(prevProps) {
if (this.props.isModalOpen === true && prevProps.isModalOpen === false) {
this.handlePreFillModalInputsOnOpen();
}
}
Watch out
make sure that you have a conditional in componentDidUpdate, otherwise you can run into infinite-loop/performance issues
if you have the possibility of null values icoming in as the prefilled input info, make a null-check so that they will not be passed into the local state.
Hope this helps :)
How to Programmatically Prefill, Fill or Update input fields value in React or useState Hooks?
Firstly - Get and define the data from database
const **yourData** = isDataFromDatabase;
or if the data is stored in Redux, then...
const **yourData** = useSelector(isDataFromDatabase);
Secondly - append it as the default value of a useState hook
const [isDataValue, setIsDataValue] = useState(**yourData**);
Thirdly - create a function to watch and Update the changes made by the user to your data value and set it to the useState hook created above
/** handles Your Data Value */
const handleDataValue = (text) => {
setIsDataValue(text);
};
Lastly - in your input tag, use the useState State as the "Value" parameter so it can be updated with the onChange function
<input
className="css"
id="myDataInput"
type="text"
value={isDataValue}
placeholder={isDataValue}
onChange={(e) => handleDataValue(e.target.value)}
/>
Now when you load the component, the prefilled value will be shown and can be updated in the HTML Input field.
That's All.
I have a dropdown I want to be pre-selected when the data is available. However there appears to be no real chance for that?
Since I am waiting for a change in state for a particular value using that value as the value= causes the selections to be unselectable, while using it as a defaultValue= causes the UI to not recognize the value unless a change to the element has been made meaning if the user decides to go with the default choice it wouldn't be passed up the to the API I am trying to pass it up to.
Is there a way to dynamically change a select box after the dom is ready after the components mounted and when a state is changed?
It's a bit difficult without seeing the code, but have you tried setting the value into the React component's state and rendering that instead? You can also read the state's value instead of the DropDown's.
getInitialState: function () {
return {
dropDownSelection: "some default value"
};
},
handleSelectionChanged: function (e) {
this.setState({
dropDownSelection: e.target.value
});
},
render: function () {
return (
//...
<select className="form-control" value={this.state.dropDownSelection} onChange={this.handleSelectionChanged}>
//...
</select>
);
}