#reactjs #react-hooks #state
#reactjs #реагирующие хуки #состояние
Вопрос:
Я совсем новичок в React и не всегда понимаю, когда мне нужно использовать хуки, а когда они мне не нужны.
Я понимаю, что вы можете получить / установить состояние, используя
const [myState, setMyState] = React.useState(myStateValue);
Итак. Мой компонент выполняет некоторые функции на основе URL-адреса :
const playlist = new PlaylistObj();
React.useEffect(() => {
playlist.loadUrl(props.url).then(function(){
console.log("LOADED!");
})
}, [props.url]);
Внутри моего класса PlaylistObj у меня есть асинхронная функция loadUrl (url), которая
- устанавливает для свойства apiLoading списка воспроизведения значение true
- получает содержимое
- устанавливает для свойства apiLoading списка воспроизведения значение false
Теперь я хочу использовать это значение в своем компоненте React, чтобы я мог задавать его классы (я использую classnames) :
<div
className={classNames({
'api-loading': playlist.apiLoading
})}
>
Но это не работает; класс не обновляется, даже если я получаю сообщение «ЗАГРУЖЕНО!» в консоли.
Кажется, что объект списка воспроизведения не «просматривается» React. Может быть, мне следует использовать здесь состояние реакции, но как?
Я тестировал
const = React.useState(new PlaylistObj());
React.useEffect(() => {
//refresh playlist if its URL is updated
playlist.loadUrl(props.playlistUrl).then(function(){
console.log("LOADED!");
})
}, [props.playlistUrl]);
И это, но мне это кажется все более и более нелогичным, и, ну, не работает.
const = React.useState(new PlaylistObj());
React.useEffect(() => {
playlist.loadUrl(props.playlistUrl).then(function(){
console.log("LOADED!");
setPlaylist(playlist); //added this
})
}, [props.playlistUrl]);
Я просто хочу, чтобы мой компонент был обновлен с помощью объекта списка воспроизведения. Как мне с этим справиться?
Я чувствую, что что-то упускаю.
Большое спасибо!
Ответ №1:
Я думаю, вы близки, но в основном эта проблема заключается в том, что вы фактически не обновляете ссылку на состояние, чтобы вызвать другой повторный запуск с правильным значением загрузки.
const = React.useState(new PlaylistObj());
React.useEffect(() => {
playlist.loadUrl(props.playlistUrl).then(function(){
setPlaylist(playlist); // <-- this playlist reference doesn't change
})
}, [props.playlistUrl]);
Я думаю, вам следует ввести второе isLoading
состояние для вашего компонента. Когда эффект срабатывает при обновлении URL-адреса, начните с установки loading true , а когда обещание будет выполнено, обновите его обратно на false.
const = React.useState(new PlaylistObj());
const [isloading, setIsLoading] = React.useState(false);
React.useEffect(() => {
setIsLoading(true);
playlist.loadUrl(props.playlistUrl).then(function(){
console.log("LOADED!");
setIsLoading(false);
});
}, [props.playlistUrl]);
Используйте isLoading
состояние при рендеринге
<div
className={classNames({
'api-loading': isLoading,
})}
>
Я также предлагаю использовать finally
блок цепочки обещаний для завершения загрузки в случае, если обещание отклонено, ваш пользовательский интерфейс не застревает в «состоянии» загрузки.
React.useEffect(() => {
setIsLoading(true);
playlist.loadUrl(props.playlistUrl)
.then(function() {
console.log("LOADED!");
})
.finally(() => setIsLoading(false));
}, [props.playlistUrl]);
Ответ №2:
Вот и все:
import React from "react";
class PlaylistAPI {
constructor(data = []) {
this.data = data;
this.listeners = [];
}
addListener(fn) {
this.listeners.push(fn);
}
removeEventListener(fn) {
this.listeners = this.listeners.filter(prevFn => prevFn !== fn)
}
setPlayList(data) {
this.data = data;
this.notif();
}
loadUrl(url) {
console.log("called loadUrl", url, this.data)
}
notif() {
this.listeners.forEach(fn => fn());
}
}
export default function App() {
const API = React.useMemo(() => new PlaylistAPI(), []);
React.useEffect(() => {
API.addListener(loadPlaylist);
/**
* Update your playlist and when user job has done, listerners will be called
*/
setTimeout(() => {
API.setPlayList([1,2,3])
}, 3000)
return () => {
API.removeEventListener(loadPlaylist);
}
}, [API])
function loadPlaylist() {
API.loadUrl("my url");
}
return (
<div className="App">
<h1>Watching an object by React Hooks</h1>
</div>
);
}
Комментарии:
1. Хорошо, итак, вы используете здесь запоминание. В чем было бы преимущество использования этого, а не контекста React? Спасибо.
2. Он делает это, принимая функцию, которая возвращает значение, а затем эта функция вызывается только тогда, когда значение должно быть извлечено (что обычно происходит только один раз каждый раз, когда элемент в массиве зависимостей изменяется между отображениями).