I am using a plugin named react-native-masonry-list to show the list of data in masonry view which works fine.But when i try to update a value in the data.The value gets updated but it is not reflected in the masonry list.I have checked the props in which the data gets updated.
When i saw the code in the plugin it has mentioned that only during the image / orientation / size gets changed the data is refreshed and state gets updated.
I would like to add a function like once the data gets changed it should refresh the list.But i don't know how to inherit the plugin without making any changes in their code.
Plugin Link: react-native-masonry-list
<MasonryList
sorted={true}
imageContainerStyle={styles.masonryImgView}
onPressImage={this.onSelectBranchItem}
renderIndividualHeader={res => {
return (
<DealsMasonryHeader
data={res}
onSelectedDeal={this.onSelectedDeal}
onSelectedFavourite={this.onSelectedFavourite.bind(this, res)}
favDisable={res.isfavourite}
onMapOpen={this.onMapOpen.bind(this, res)}
onSocialShare={this.socialShare.bind(this, res)}
/>
);
}}
renderIndividualFooter={res => {
return (
<DealsMasonryFooter
data={res}
onItemPress={this.onSelectBranchItem.bind(this, res)}
/>
);
}}
images={filterData}
/>
FilterData:
const { dealsList, currentUser } = this.props;
const { searchText, selectedBranchItem } = this.state;
let re = new RegExp(searchText, 'i');
const filterData = dealsList
? dealsList.filter((deal) => {
return !!(
deal.title.match(re) ||
deal.discount_percentage.toString().match(re) ||
deal.tags.toString().match(re)
);
})
: [];
I want to know whether it is possible to inherit a component in react native
In the react-native-masonry-list plugin -> MasonryList.js
componentWillReceiveProps = (nextProps) => {
if (nextProps.layoutDimensions.width && nextProps.layoutDimensions.height &&
nextProps.layoutDimensions.columnWidth && nextProps.layoutDimensions.gutterSize &&
nextProps.layoutDimensions.width !== this.props.layoutDimensions.width &&
nextProps.layoutDimensions.height !== this.props.layoutDimensions.height &&
!this.props.containerWidth) {
this.resolveImages(
nextProps.itemSource,
nextProps.images,
nextProps.layoutDimensions,
nextProps.columns,
nextProps.sorted
);
}
else if (nextProps.orientation !== this.props.orientation ||
nextProps.columns !== this.props.columns ||
nextProps.spacing !== this.props.spacing ||
nextProps.sorted !== this.props.sorted ||
nextProps.containerWidth !== this.props.containerWidth) {
this.resolveImages(
nextProps.itemSource,
this._calculatedData,
nextProps.layoutDimensions,
nextProps.columns,
nextProps.sorted
);
}
else if (nextProps.images !== this.props.images) {
this.resolveImages(
nextProps.itemSource,
nextProps.images,
nextProps.layoutDimensions,
nextProps.columns,
nextProps.sorted
);
}
}
Related
MUI DataGrid
onCellEditStop changes value of previously edited cell when changing other cell.
I saw a post that said that using onCellEditCommit is a solution, but it's deprecated so.. I need another way to fix it
const onCellEditStopHandler = (params: GridCellParams) => {
const { id, field, value } = params;
const faction = staffFactions.find((faction) => faction.id === id);
console.log('triggered');
if (!faction) return;
const factionWithoutActive = staffFactions.filter(
(faction) => faction.id !== id
);
if (field === 'maxVehicles') {
faction.maxVehicles = value;
} else if (field === 'maxMembers') {
faction.maxMembers = value;
}
setStaffFactions([...factionWithoutActive, faction]);
};
<ReactDataGrid
experimentalFeatures={{ newEditingApi: true }}
rows={rows || []}
columns={columns}
onCellEditStop={onCellEditStopHandler}
/>
In the docs, there are many ways that you could handle an editable component.
https://mui.com/x/react-data-grid/editing
For your code, maybe you could check out this section below and try using the processRowUpdate prop. It gets called once the editing stops.
https://mui.com/x/react-data-grid/editing/#persistence
I'm trying to create a re-usable component that wraps similar functionality where the only things that change are a Title string and the data that is used to populate a Kendo ComboBox.
So, I have a navigation menu that loads (at the moment) six different filters:
{
context && context.Filters && context.Filters.map((item) => getComponent(item))
}
GetComponent gets the ID of the filter, gets the definition of the filter from the context, and creates a drop down component passing in properties:
function getComponent(item) {
var filterDefinition = context.Filters.find(filter => filter.Id === item.Id);
switch (item.DisplayType) {
case 'ComboBox':
return <DropDownFilterable key={item.Id} Id={item.Id} Definition={filterDefinition} />
default:
return null;
}
}
The DropDownFilterable component calls a service to get the data for the combo box and then loads everything up:
const DropDownFilterable = (props) => {
const appService = Service();
filterDefinition = props.Definition;
console.log(filterDefinition.Name + " - " + filterDefinition.Id);
React.useEffect(() => {
console.log("useEffect: " + filterDefinition.Name + " - " + filterDefinition.Id);
appService.getFilterValues(filterDefinition.Id).then(response => {
filterData = response;
})
}, []);
return (
<div>
<div className="row" title={filterDefinition.DisplayName}>{filterDefinition.DisplayName}</div>
<ComboBox
id={"filterComboBox_" + filterDefinition.Id}
data={filterData}
//onOpen={console.log("test")}
style={{zIndex: 999999}}
dataItemKey={filterDefinition && filterDefinition.Definition && filterDefinition.Definition.DataHeaders[0]}
textField={filterDefinition && filterDefinition.Definition && filterDefinition.Definition.DataHeaders[1]}
/>
</div>
)
}
Service call:
function getFilterValues(id) {
switch(id) {
case "E903B2D2-55DE-4FA3-986A-8A038751C5CD":
return fetch(Settings.url_getCurrencies).then(toJson);
default:
return fetch(Settings.url_getRevenueScenarios).then(toJson);
}
};
What's happening is, the title (DisplayName) for each filter is correctly rendered onto the navigation menu, but the data for all six filters is the data for whichever filter is passed in last. I'm new to React and I'm not 100% comfortable with the hooks yet, so I'm probably doing something in the wrong order or not doing something in the right hook. I've created a slimmed-down version of the app:
https://codesandbox.io/s/spotlight-react-full-forked-r25ns
Any help would be appreciated. Thanks!
It's because you are using filterData incorrectly - you defined it outside of the DropDownFilterable component which means it will be shared. Instead, set the value in component state (I've shortened the code to include just my changes):
const DropDownFilterable = (props) => {
// ...
// store filterData in component state
const [filterData, setFilterData] = React.useState(null);
React.useEffect(() => {
// ...
appService.getFilterValues(filterDefinition.Id).then(response => {
// update filterData with response from appService
setFilterData(response);
})
}, []);
// only show a ComboBox if filterData is defined
return filterData && (
// ...
)
}
Alternatively you can use an empty array as the default state...
const [filterData, setFilterData] = React.useState([]);
...since the ComboBox component accepts an array for the data prop. That way you won't have to conditionally render.
Update
For filterDefinition you also need to make sure it is set properly:
const [filterDefinition, setFilterDefinition] = React.useState(props.Definition);
// ...
React.useEffect(() => {
setFilterDefinition(props.Definition);
}, [props.Definition]);
It may also be easier to keep filterDefinition out of state if you don't expect it to change:
const filterDefinition = props.Definition || {};
I have a Detail list, based on the condition I need to show columns. If I am doing below approach then Its working fine, but on render method
return (
<DetailsList
isLoading={isLoading(this.props.loadProgress)}
items={this.props.solutionSubcomponents}
columns={
this.props.solutionSubcomponents.length > 0 &&
this.props.solutionSubcomponents[0].subcomponentType.logicalName ===
SolutionComponentTypes.EntityRelationship.logicalName
? this.buildColumns()
: this.buildRelationshipColumns()
}
renderOnEmpty={() => {
let props = this.getPropsOnEmpty();
return <EmptyState {...props} />;
}}
filter={this.props.searchFilter}
renderOnEmptySearch={() => {
let props = this.getPropsOnEmptySearch();
return <EmptyState {...props} />;
}}
This code is working fine but as this is not a good approach so I wnat to handle this on ComponentDidMount but not able to get the previous props value.
public componentDidUpdate(prevProps: ISolutionSubcomponentListProps): void {
if (
this.props.solutionSubcomponents.length > 0 &&
prevProps.solutionSubcomponents.length > 0 &&
this.props.solutionSubcomponents[0].subcomponentType.logicalName !==
prevProps.solutionSubcomponents[0].subcomponentType.logicalName
) {
if (
this.props.solutionSubcomponents.length > 0 &&
this.props.solutionSubcomponents[0].subcomponentType.logicalName ===
SolutionComponentTypes.EntityRelationship.logicalName
) {
this.columns = this.buildRelationshipColumns();
}
}
}
Please suggest how I can set the dynamic column to react life-cycle method instead of render method of detail list.
I'm trying to add a video player, I'm using react-native-video-controls to add controls on my video but it has a problem with resetting a pause
code:
handleExitFullScreen = () => {
this.setState({
fullScreen : false
});
}
handleEnterFullscreen = () => {
this.setState({
fullScreen : true
});
}
<VideoPlayer
source = {{ uri: link }}
disableVolume
disableBack
onEnterFullscreen = {this.handleEnterFullscreen}
onExitFullscreen = {this.handleExitFullScreen}
toggleResizeModeOnFullscreen = {false}
/>
If you look at the react-native-video-controls module,
_toggleFullscreen() {
let state = this.state;
state.isFullscreen = ! state.isFullscreen;
if (this.props.toggleResizeModeOnFullscreen) {
state.resizeMode = state.isFullscreen === true ? 'cover' : 'contain';
}
if (state.isFullscreen) {
typeof this.events.onEnterFullscreen === 'function' && this.events.onEnterFullscreen();
}
else {
typeof this.events.onExitFullscreen === 'function' && this.events.onExitFullscreen();
}
this.setState( state );
}
you can see that it executes setSate when changing the status of the screen. That means being rendered again.
The implementations are included in such renderers as react-native-dom, react-native.
Looking at the setState implementation in React.Component, everything was delegated to act on the renderer that created the component instance.
// A bit simplified
setState(partialState, callback) {
// Use the 'updater' field to talk back to the renderer!
this.updater.enqueueSetState(this, partialState, callback);
};
This is how this.setState() is defined in the React package, but it is how DOM is updated.
Read this.updater set by React DOM, allow ReactDOM schedule, and process updates.
I have a form that contains several questions. Some of the questions contains a group of subquestions.
{
(this.props.moduleDetails.questions[questionInfo].question_group && this.props.moduleDetails.questions[questionInfo].has_grouped_questions === 1) ?
<div className="sub-questions">
{
(this.props.moduleDetails.questions[questionInfo].question_group ) ?
<span>
{ this.renderQuestionGroup(questionInfo) }
<input type="button" onClick={(e) => { this.addQuestionGroup(questionInfo) }} value="Add" className="btn"/>
</span>
: null
}
</div>
: null
}
As you can see, renderQuestionGroup is the method that displays the sub-questions.
renderQuestionGroup(questionInfo) {
let input = [];
input = this.display(questionInfo)
return input;
}
display(questionInfo) {
let input = [];
this.state && this.state.groupedQuestions && this.state.groupedQuestions[questionInfo] && this.state.groupedQuestions[questionInfo].map(
(qInfo, qIndex) => {
if(qInfo !== undefined) {
Object.keys(qInfo).map(
(questionInfo, index) => {
input.push(<QuestionAnswers
questionInfo={qInfo[questionInfo]}
generateStepData={this.props.generateStepData}
userEnteredValues={this.props.formValues}
key={qInfo[questionInfo].module_question_id+qIndex}
groupIndex={qIndex}
/>)
});
}
});
return input;
}
Subquestions (a group of questions) are placed in state during the componentDidUpdate.
componentDidUpdate = (prevProps, prevState, snapshot) => {
console.log('prevProps----------->', prevProps);
console.log('this.props----------->', this.props)
if (prevProps !== this.props) {
let questions = this.props.moduleDetails.questions,
sgq = {};
Object.keys(questions).map((qId) => {
sgq[qId] = (this.state.groupedQuestions[qId]) ? this.state.groupedQuestions[qId] : [];
let answerId = this.props.formValues[qId],
questionObj = questions[qId],
groupedQuestions = [];
if(questionObj.has_grouped_questions == 1 && answerId != null && (this.state.groupedQuestions != null)) {
groupedQuestions = questions[qId].question_group[answerId];
let loopCount = this.getLoopCount(groupedQuestions);
for(let i=0; i<loopCount; i++) {
sgq[qId].push(groupedQuestions);
}
}
});
this.setState({groupedQuestions: sgq});
}
}
This works well and the questions get loaded correctly initially. The problem is that during every handleChange event, the method componentDidUpdate is getting triggered which eventually leads to rendering questions again.
I dont want the componentDidUpdate method to invoke during the handlechange event. Any idea on how to fix this?
PS: My idea was to compare prevProps and this.props. If both are not same, it will be handle change event. But the issue is that if i remove the condition
if (prevProps !== this.props) {
...
}
I am getting an infinite loop during initial load. So what i need is as follows.
Detect handleChange inside componentDidUpdate method.
Questions to render correctly initially. Currently i am getting an infinite loop if i remove the if (prevProps !== this.props) { ...} condition.
Any help would be appreciated.
componentDidUpdate is triggered on each change of the state, this is why you can get infinite loops when you set the state there.
If your new data is coming from from props then move this logic to getderivedstatefromprops (or componentWillReceiveProps if you are using lower version of react below v16.3).
getderivedstatefromprops
componentWillReceiveProps
As for handle change just set the state inside the handler, no need to listen for changes in componentDidUpdate.