У меня есть компонент просмотра списка и календаря в родительском компоненте.Для компонента календаря я хочу иметь возможность отправлять поисковые фильтры на мой URL для фильтрации невыбранных местоположений.Я пытаюсь сгенерировать строку запроса на основе параметров, которые я предоставляю своей функции queryString, но когда я помещаю queryString в свой URL, я получаю следующую ошибку:
Между диспетчерами обнаружена мутация состоянияв пути locations.calendarLocationList.0
.Это может вызвать неправильное поведение.(http://redux.js.org/docs/Troubleshooting.html#never-mutate-reducer-arguments)
Я не уверен, что является причиной этого, так как я не затрагивал состояние во время этого процесса.
Родительский компонент, список рендеринга ипредставление календаря
class LocationShell extends Component<
LocationShellProps & WithNamespaces & RouteComponentProps,
LocationShellState
> {
constructor(props: LocationShellProps & WithNamespaces & RouteComponentProps) {
super(props);
this.state = {
isCalendarView: false,
open: false,
locationIdToDelete: -1,
activePage: 1,
activeSortHeader: undefined,
direction: 'ascending',
searchValue: undefined
};
}
componentDidMount = (
{ loadLocations, loadSessionLocations, loadCalendarListLocations } = this.props,
{ activePage } = this.state
) => {
loadLocations({ page: activePage });
loadSessionLocations();
loadCalendarListLocations();
};
toggleView = () => {
const { isCalendarView } = this.state;
this.setState((prevState) => ({
...prevState,
isCalendarView: !isCalendarView
}))
}
renderListView = () => {
const { locationStatus, locations, selectedLocationId, history, match, pages, t } = this.props;
const { activePage, activeSortHeader, direction } = this.state;
switch (locationStatus) {
case ProgressStatus.InProgress:
return <InitialLoader />
case ProgressStatus.Done:
return (
<DataTableWrapper
// props
/>
)
case ProgressStatus.Error:
return <NoDataFound />
case ProgressStatus.Uninitialized:
return null
}
}
renderCalendarView = ({ calendarListStatus, sessionLocations, calendarListLocations } = this.props) => {
switch (calendarListStatus) {
case ProgressStatus.InProgress:
return <InitialLoader />
case ProgressStatus.Done:
const events = toLocationEvents(sessionLocations!);
return <CalendarView {...this.props} events={events} items={calendarListLocations!} name={'locations'} />
case ProgressStatus.Error:
return <NoDataFound />
case ProgressStatus.Uninitialized:
return null
}
}
render() {
const { pathName, t } = this.props;
const { isCalendarView } = this.state;
return (
<Fragment>
<PageHeader
breadCrumbParts={split(pathName, '/').map(x => t(x))}
title={t('moduleTitle')}
/>
<Button.Group size="mini" style={{ padding: '10px 5px 10px 0px' }}>
<Button positive={!isCalendarView} onClick={this.toggleView}>Lijst</Button>
<Button.Or />
<Button positive={isCalendarView} onClick={this.toggleView}>Kalender</Button>
</Button.Group>
<Button
positive
icon='add'
size="mini"
labelPosition='right'
content="Nieuwe locatie"
onClick={() => this.props.history.push(this.props.match.path + '/create')}
/>
{isCalendarView ? this.renderCalendarView() : this.renderListView()}
</Fragment>
);
}
}
const mapStateToProps = (state: GlobalState) => {
return {
locations: getLocations(state.locations),
calendarListLocations: state.locations.calendarLocationList,
calendarListStatus: state.locations.calendarListStatus,
sessionLocations: state.locations.sessionLocations,
selectedLocation: getSelectedLocation(state.locations),
selectedLocationId: getSelectedLocationId(state.locations),
pages: getAmountPages(state.locations),
locationStatus: state.locations.locationStatus,
sessionLocationStatus: state.locations.sessionLocationStatus,
pathName: getPathName(state.router)
};
};
const mapDispatchToProps = (dispatch: Dispatch) => ({
loadLocations: (queryParams: QueryParams) =>
dispatch(FetchLocations(queryParams)),
loadSessionLocations: () => dispatch(FetchTrainingSessionLocations({})),
loadCalendarListLocations : () => dispatch(FetchCalendarListLocations({})),
clearLocations: () => dispatch(ClearLocations()),
deleteLocation: (id: number) => dispatch(DeleteLocation({ locationId: id }))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(withNamespaces('locations')(LocationShell));
renderCalendarView()
отображает компонент моего календаря
Мой компонент календаря:
interface CalendarViewState {
selectedIds: number[];
}
type CalendarViewProps = {
events: CalendarEvent[];
name: string;
items: CalendarListLocation[];
navigatePush: (values: string) => void;
} & RouteComponentProps
class CalendarView extends Component<CalendarViewProps & WithNamespaces, CalendarViewState> {
state: CalendarViewState = {
selectedIds: []
}
componentDidMount = () => {
const { events, items } = this.props;
const { baseUrl, newEntity } = moduleConstants;
this.setState((prevState) => ({
...prevState,
selectedIds: items.map(x => x._id)
}), () => {
updateQueryString(this.props, { page: 1, locations: [1, 2] })
}
)
}
queryParams(props: CalendarViewProps = this.props) {
return queryParams<QueryParams>(props.location.search);
}
componentDidUpdate = (prevProps: CalendarViewProps, prevState: CalendarViewState) => {
const { selectedIds } = this.state;
console.log()
if (!isEqual(prevState.selectedIds, selectedIds)) {
console.log(this.queryParams())
}
}
handleChange = (id: number) => {
const { selectedIds } = this.state;
this.setState((prevState) => ({
...prevState,
selectedIds: (selectedIds.includes(id) ? selectedIds.filter(x => x !== id) : [...selectedIds, id])
}));
};
render() {
const { events, name, t, items } = this.props
return (
<Grid divided="vertically" padded>
<Grid.Row columns={2}>
<Grid.Column width={4}>
<CalendarSelectionList
name={t(name)}
onSelectionChange={this.handleChange}
selectedIds={this.state.selectedIds}
locations={items.sort((a: CalendarListLocation, b: CalendarListLocation) => a.name.localeCompare(b.name))}
/>
</Grid.Column>
<Grid.Column width={12}>
<div style={{ height: '800px' }}>
<Calendar
events={events.filter(x => this.state.selectedIds.includes(x.id))}
/>
</div>
</Grid.Column>
</Grid.Row>
</Grid>
);
}
}
const mapDispatchToProps = (dispatch: Dispatch) => ({
navigatePush: (path: string) => dispatch(push(path))
});
export default connect(
null,
mapDispatchToProps
)(withNamespaces(['calendar'])(CalendarView));
updateQueryString(this.props, { page: 1, locations: [1, 2] })
Когда эта функция запускается, эта функция обновляет URL-адрес сгенерированным queryString
export function queryParams<T>(search: string) {
return (queryString.parse(search) as unknown) as T;
}
export function updateQueryString<T>(props: RouteComponentProps, newValues: T) {
const currentQuery = queryParams<T>(props.location.search);
const newProps = Object.assign(currentQuery, newValues);
props.history.push({
pathname: props.location.pathname,
search: queryString.stringify(filterSearchResults(newProps))
});
}
function filterSearchResults(values: any) {
let obj: any = {};
Object.keys(values).forEach(
key => values[key] && (obj[key] = values[key])
);
return obj;
}
. После этого возникает вышеуказанная ошибка. Почему происходит эта ошибка?