Refactor "New/Edit list" page to avoid setting state in effect (#36753)

This commit is contained in:
diondiondion 2025-11-06 12:00:37 +01:00 committed by GitHub
parent 41a4022988
commit 58b3fc0379
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -22,6 +22,7 @@ import { Column } from 'mastodon/components/column';
import { ColumnHeader } from 'mastodon/components/column_header'; import { ColumnHeader } from 'mastodon/components/column_header';
import { Icon } from 'mastodon/components/icon'; import { Icon } from 'mastodon/components/icon';
import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import type { List } from 'mastodon/models/list';
import { useAppDispatch, useAppSelector } from 'mastodon/store'; import { useAppDispatch, useAppSelector } from 'mastodon/store';
import { messages as membersMessages } from './members'; import { messages as membersMessages } from './members';
@ -72,36 +73,23 @@ const MembersLink: React.FC<{
); );
}; };
const NewList: React.FC<{ const NewList: React.FC<{ list?: List | null }> = ({ list }) => {
multiColumn?: boolean;
}> = ({ multiColumn }) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { id } = useParams<{ id?: string }>();
const intl = useIntl();
const history = useHistory(); const history = useHistory();
const list = useAppSelector((state) => const {
id ? state.lists.get(id) : undefined, id,
); title: initialTitle = '',
const [title, setTitle] = useState(''); exclusive: initialExclusive = false,
const [exclusive, setExclusive] = useState(false); replies_policy: initialRepliesPolicy = 'list',
const [repliesPolicy, setRepliesPolicy] = useState<RepliesPolicyType>('list'); } = list ?? {};
const [title, setTitle] = useState(initialTitle);
const [exclusive, setExclusive] = useState(initialExclusive);
const [repliesPolicy, setRepliesPolicy] =
useState<RepliesPolicyType>(initialRepliesPolicy);
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
useEffect(() => {
if (id) {
dispatch(fetchList(id));
}
}, [dispatch, id]);
useEffect(() => {
if (id && list) {
setTitle(list.title);
setExclusive(list.exclusive);
setRepliesPolicy(list.replies_policy);
}
}, [setTitle, setExclusive, setRepliesPolicy, id, list]);
const handleTitleChange = useCallback( const handleTitleChange = useCallback(
({ target: { value } }: React.ChangeEvent<HTMLInputElement>) => { ({ target: { value } }: React.ChangeEvent<HTMLInputElement>) => {
setTitle(value); setTitle(value);
@ -159,19 +147,6 @@ const NewList: React.FC<{
}, [history, dispatch, setSubmitting, id, title, exclusive, repliesPolicy]); }, [history, dispatch, setSubmitting, id, title, exclusive, repliesPolicy]);
return ( return (
<Column
bindToDocument={!multiColumn}
label={intl.formatMessage(id ? messages.edit : messages.create)}
>
<ColumnHeader
title={intl.formatMessage(id ? messages.edit : messages.create)}
icon='list-ul'
iconComponent={ListAltIcon}
multiColumn={multiColumn}
showBackButton
/>
<div className='scrollable'>
<form className='simple_form app-form' onSubmit={handleSubmit}> <form className='simple_form app-form' onSubmit={handleSubmit}>
<div className='fields-group'> <div className='fields-group'>
<div className='input with_label'> <div className='input with_label'>
@ -264,10 +239,7 @@ const NewList: React.FC<{
<div className='app-form__toggle__toggle'> <div className='app-form__toggle__toggle'>
<div> <div>
<Toggle <Toggle checked={exclusive} onChange={handleExclusiveChange} />
checked={exclusive}
onChange={handleExclusiveChange}
/>
</div> </div>
</div> </div>
</label> </label>
@ -285,6 +257,42 @@ const NewList: React.FC<{
</button> </button>
</div> </div>
</form> </form>
);
};
const NewListWrapper: React.FC<{
multiColumn?: boolean;
}> = ({ multiColumn }) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const { id } = useParams<{ id?: string }>();
const list = useAppSelector((state) =>
id ? state.lists.get(id) : undefined,
);
useEffect(() => {
if (id) {
dispatch(fetchList(id));
}
}, [dispatch, id]);
const isLoading = id && !list;
return (
<Column
bindToDocument={!multiColumn}
label={intl.formatMessage(id ? messages.edit : messages.create)}
>
<ColumnHeader
title={intl.formatMessage(id ? messages.edit : messages.create)}
icon='list-ul'
iconComponent={ListAltIcon}
multiColumn={multiColumn}
showBackButton
/>
<div className='scrollable'>
{isLoading ? <LoadingIndicator /> : <NewList list={list} />}
</div> </div>
<Helmet> <Helmet>
@ -298,4 +306,4 @@ const NewList: React.FC<{
}; };
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default NewList; export default NewListWrapper;