我正在学习教程,并在客户端应用程序中使用react + mobx +打字稿,并在后端使用dotnet核心Web API 3.1。一切都在后端运行
我面临的问题是在创建CRUD中。创建后,@ observable活动将更新,但视图不会反映所做的更改。在useEffect中,我正在加载所有活动。创建活动时不会调用它。
再次创建活动,但未在视图上呈现活动。页面刷新时显示。
activityStore.ts
是@observable activities
,@action loadActivities
和@action createActivity
所在的存储文件App.tsx
是我正在调用useEffect
来加载所有活动的文件。ActivityList.tsx
组成列表的组件ActivityForm.tsx
是创建活动的表单组件而不是在这里显示我的代码,我认为共享我的GitHub链接会更好:https://github.com/safiullah7/Reactivities
反应代码是:https://github.com/safiullah7/Reactivities/tree/master/client-app
activityStore.ts:
import {observable, action, computed} from 'mobx';
import { createContext } from 'react';
import { IActivity } from '../models/activity';
import agent from '../api/agent';
class ActivityStore {
@observable activities: IActivity[] = [];
@observable loadingInitial = false;
@observable selectedActivity: IActivity | undefined;
@observable editMode = false;
@observable submitting = false;
@action loadActivities = async () => {
this.loadingInitial = true;
debugger;
try {
let activities = await agent.Activities.list();
activities.forEach(activity => {
activity.date = activity.date.split('.')[0];
this.activities.push(activity);
});
this.loadingInitial = false;
} catch (error) {
this.loadingInitial = false;
console.log(error);
}
}
@action createActivity = async (activity: IActivity) => {
this.submitting = true;
try {
debugger;
await agent.Activities.create(activity);
let activities = [...this.activities, activity]
this.activities = activities;
//this.selectedActivity = activity;
this.editMode = false;
this.submitting = false;
} catch (error) {
//this.editMode = false;
this.submitting = false;
console.log(error);
}
}
@action openCreateForm = () => {
this.selectedActivity = undefined;
this.editMode = true;
}
@action selectActivity = (id: string) => {
this.selectedActivity = this.activities.find(a => a.id === id);
this.editMode = false;
}
}
export default createContext(new ActivityStore());
App.tsx:
import React, { useState, useEffect, Fragment, SyntheticEvent, useContext } from 'react';
import { Container } from 'semantic-ui-react'
import { IActivity } from '../models/activity';
import NavBar from '../../features/nav/NavBar';
import ActivityDashboard from '../../features/activities/dashboard/ActivityDashboard';
import agent from '../api/agent';
import LoadingComponent from './LoadingComponent';
import ActivityStore from '../stores/activityStore';
import {observer} from 'mobx-react-lite';
const App = () => {
const activityStore = useContext(ActivityStore);
const [activities, setActivities] = useState<IActivity[]>([]);
const [selectedActivity, setSelectedActivity] = useState<IActivity | null>(null);
const [editMode, setEditMode] = useState<Boolean>(false);
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [target, setTarget] = useState('');
useEffect(() => {
activityStore.loadActivities();
}, [activityStore]);
// to run this once and not infinitly to keep getting the data
// when state changes, useEffect is called. So it will become infinite loop
const handleEditActivity = (activity: IActivity) => {
setSubmitting(true);
agent.Activities.update(activity).then(() => {
setActivities([...activities.filter(a => a.id !== activity.id), activity]);
setSelectedActivity(activity);
setEditMode(false);
}).then(() => setSubmitting(false));
};
const handleDeleteActivity = (event:SyntheticEvent<HTMLButtonElement>,id: string) => {
setTarget(event.currentTarget.name);
setSubmitting(true);
agent.Activities.delete(id).then(() => {
setActivities([...activities.filter(a => a.id !== id)]);
}).then(() => setSubmitting(false));
};
if (activityStore.loadingInitial)
return <LoadingComponent content='Loading activities...'/>
else
return (
<Fragment>
<NavBar />
<Container style={{marginTop: '7em'}}>
<ActivityDashboard
setEditMode={setEditMode}
setSelectedActivity={setSelectedActivity}
editActivity={handleEditActivity}
deleteActivity={handleDeleteActivity}
submitting={submitting}
target={target}
/>
</Container>
</Fragment>
);
}
export default observer(App);
ActivityList.tsx:
import React, { SyntheticEvent, useContext, useEffect } from 'react'
import { Item, Button, Label, Segment } from 'semantic-ui-react';
import { IActivity } from '../../../app/models/activity';
import { observer } from 'mobx-react-lite';
import ActivityStore from '../../../app/stores/activityStore';
interface IProps {
deleteActivity: (e:SyntheticEvent<HTMLButtonElement>, id: string) => void,
submitting: boolean,
target: string
}
const ActivityList: React.FC<IProps> = ({ deleteActivity, submitting, target }) => {
const activityStore = useContext(ActivityStore);
let {activities, selectActivity} = activityStore;
return (
// floating right in the item. need to clear other floats
<Segment clearing>
<Item.Group divided>
{activities.map(activity => {
return (
<Item key={activity.id}>
<Item.Content>
<Item.Header as='a'>{activity.title}</Item.Header>
<Item.Meta>{activity.date}</Item.Meta>
<Item.Description>
<div>{activity.description}</div>
<div>{activity.city}, {activity.venue}</div>
</Item.Description>
<Item.Extra>
<Button floated='right' content='View' color='blue'
onClick={() => selectActivity(activity.id)}
/>
<Button name={activity.id} loading={target === activity.id && submitting} floated='right' content='Delete' color='red'
onClick={(e) => deleteActivity(e,activity.id)}
/>
<Label basic content={activity.category} />
</Item.Extra>
</Item.Content>
</Item>
);
})}
</Item.Group>
</Segment>
);
};
export default observer(ActivityList);
ActivityForm.tsx:
import React, {useState, FormEvent, useContext} from 'react'
import { Segment, Form, Button } from 'semantic-ui-react';
import { IActivity } from '../../../app/models/activity';
import {v4 as uuid} from 'uuid';
import ActivityStore from '../../../app/stores/activityStore';
import { observer } from 'mobx-react-lite';
interface IProps {
setEditMode: (editMode: Boolean) => void
activity: IActivity,
editActivity: (activity: IActivity) => void,
submitting: boolean
}
const ActivityForm: React.FC<IProps> =
({ setEditMode, activity: initalFormState, editActivity, submitting }) => {
const activityStore = useContext(ActivityStore);
const {createActivity} = activityStore;
const initializeForm = () => {
if (initalFormState) {
return initalFormState;
} else {
return {
id: '',
title: '',
description: '',
category: '',
date: '',
city: '',
venue: '',
}
}
};
const [activity, setActivity] = useState<IActivity>(initializeForm);
const handleSubmit = () => {
if (activity.id.length === 0) {
let newActivity = {
...activity,
id: uuid(),
};
createActivity(newActivity);
} else {
editActivity(activity);
}
};
const handleInputChange = (event: FormEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const {name, value} = event.currentTarget;
setActivity({...activity, [name]: value});
}
return (
<Segment clearing>
<Form onSubmit={handleSubmit}>
<Form.Input
onChange={handleInputChange}
placeholder='Title'
name='title'
value={activity.title}/>
<Form.TextArea rows={2}
onChange={handleInputChange}
placeholder='Description'
name='description'
value={activity.description}/>
<Form.Input
onChange={handleInputChange}
placeholder='Category'
name='category'
value={activity.category}/>
<Form.Input
onChange={handleInputChange}
type='datetime-local'
name='date'
placeholder='Date'
value={activity.date}/>
<Form.Input
onChange={handleInputChange}
placeholder='City'
name='city'
value={activity.city}/>
<Form.Input
onChange={handleInputChange}
placeholder='Venue'
name='venue'
value={activity.venue}/>
<Button loading={submitting} floated='right' positive type='submit' content='Submit' />
<Button onClick={() => setEditMode(false)} floated='right' type='button' content='Cancel' />
</Form>
</Segment>
)
}
export default observer(ActivityForm);
而且,我也面临一些控制台错误。如果您也可以指导我的新手自我,我将不胜感激
PS:我是新来发问的人,如果我错过了东西,请放心,我将继续更新问题。一切都在github上tho
在ActivityForm.tsx中
<Button onClick={() => setEditMode(false)}
将在您单击后立即运行。这将导致父级卸载此组件。
在ActivityDashBoard.tsx {editMode && <ActivityForm
但是同时在[[ActivityForm.tsx中,您具有:<Form onSubmit={handleSubmit}>
在卸载组件之前,该操作没有时间完成。
const handleSubmit = () => {
if (activity.id.length === 0) {
let newActivity = {
...activity,
id: uuid()
};
createActivity(newActivity);
} else {
editActivity(activity);
}
setEditMode(false) // <-- we run it afterwards
};
另一种解决方案是不使用{editMode && <ActivityForm
,而是使用CSS / css-classs显示/隐藏。这样,您的组件将不会卸载,也不会出现此错误