Лучше ли отображать спиннеры, закусочные и т. д. в отдельных элементах DOM, а не добавлять их в основное дерево компонентов приложения? В компонентах класса React было очень легко получить ссылку на методы компонентов класса, чтобы показать/скрыть счетчик. С новыми функциональными компонентами React Hooks это уже не так просто. Если я помещу счетчик в основное дерево компонентов, смогу ли я использовать новый хук «useContext», чтобы показать/скрыть счетчик?
Ниже показан глобальный счетчик React Hooks, использующий Material-UI, который работает, но очень хакерский. Как сделать это более изящным?
namespace Spinner {
'use strict';
export let show: any; // Show method ref.
export let hide: any; // Hide method ref.
export function Render() {
const [visible, setVisible] = React.useState(false); //Set refresh method.
function showIt() {
setVisible(true); // Show spinner.
}
function hideIt() {
setVisible(false); // Hide spinner.
}
const styles: any = createStyles({
col1Container: { display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column' },
});
return (
<div>
{visible && <div style = {styles.col1Container}>
<CircularProgress key = {Util.uid()}
color='secondary'
size = {30}
thickness = {3.6}
/>
</div>}
<SetSpinnerRefs showRef = {showIt} hideRef = {hideIt} />
</div>
); // end return.
} // end function.
const mounted: boolean = true;
interface iProps {
showRef();
hideRef();
}
function SetSpinnerRefs(props: iProps) {
// ComponentDidMount.
React.useEffect(() => {
Spinner.show = props.showRef;
Spinner.hide = props.hideRef;
}, [mounted]);
return (<span />);
}
} // end module.
@estus - проблема в том, что я не понимаю, как использовать хук «useContext», поэтому я, вероятно, буду делать что-то хакерское, например, вызывать ReactDOM.render для глобального компонента счетчика каждый раз, когда я хочу его показать/скрыть.
Публикация «неправильного» stackoverflow.com/help/mcve помогла бы решить проблему более актуальным образом. useContext заменяет контекст Consumer. Если вы знаете, как сделать то, что вы описываете, пожалуйста, напишите пример. Если вы знаете, как это сделать с помощью render, вам тоже поможет пример. На данный момент вопрос слишком широк.
@estus - я добавил пример кода в этот пост, как вы и предложили. Есть ли способ сделать его более элегантным и менее хакерским?





In React class components, it was really easy to get a reference to the class components methods to show/hide the spinner
Вы можете продолжать использовать компоненты класса. Они никуда не денутся ?
На мой взгляд, на самом деле плохая практика - использовать методы класса для отображения и скрытия счетчика. Предполагая, что ваш API выглядит как
<Spinner {ref=>this.something=ref}/>
И вы используете
this.something.show(); // or .hide
<Spinner shown = {state.shown}/>
Теперь вы можете изменить state.shown вместо сохранения ссылки и использования show / hide.
Мне нравится, чтобы все было просто, и у меня есть только один глобальный компонент счетчика, который я могу показать/скрыть. Я полагаю, что в приведенном выше примере мне потребуется добавить хук состояния «показанный» к каждому компоненту в приложении, где я хочу показать/скрыть счетчик. Это правильно?
Я добавил пример кода в этот пост. Есть ли способ сделать его более элегантным и менее хакерским?
Проблема аналогична Вот этот, и решение для счетчиков будет таким же, как и для модальных окон. Хуки React не меняют его работы, но могут сделать его более лаконичным.
Предполагается, что в иерархии компонентов должен быть один экземпляр счетчика:
const SpinnerContext = React.createContext();
const SpinnerContainer = props => {
const [visible, setVisible] = React.useState(false);
const spinner = useMemo(() => ({
show: () => setVisible(true),
hide: () => setVisible(false),
}), []);
render() {
return <>
{visible && <Spinner />}
<SpinnerContext.Provider value = {spinner}>
{props.children}
</SpinnerContext.Provider>
</>;
}
}
Который передается с контекстом:
const ComponentThatUsesSpinner = props => {
const spinner = useContext(SpinnerContext);
...
spinner.hide();
...
}
<SpinnerContainer>
...
<ComponentThatUsesSpinner />
...
</SpinnerContainer>
Хотя я думаю, что ответ Basarat - это современный способ решения этой проблемы, приведенный ниже код - это то, как я это сделал. Таким образом, мне нужна только одна строка кода для создания счетчика и только одна строка кода, чтобы показать/скрыть его.
<Spinner.Render /> {/* Build spinner component */}
Spinner.show(); //Show spinner.
namespace Spinner {
'use strict';
export let show: any; //Ref to showIt method.
export let hide: any; //Ref to hideIt method.
export function Render() {
const [visible, setVisible] = React.useState(false); //Set refresh method.
function showIt() {
setVisible(true); //Show spinner.
}
function hideIt() {
setVisible(false); //Hide spinner.
}
const showRef: any = React.useRef(showIt);
const hideRef: any = React.useRef(hideIt);
//Component did mount.
React.useEffect(() => {
Spinner.show = showRef.current;
Spinner.hide = hideRef.current;
}, []);
const styles: any = createStyles({
row1Container: { display: 'flex', alignItems: 'center', justifyContent: 'center' },
});
return (
<div>
{visible && <div style = {styles.row1Container}>
<CircularProgress
color='secondary'
size = {30}
thickness = {3.6}
/>
</div>}
</div>
); //end return.
} //end function.
} //end module.