Как немедленно обновить компоненты на основе взаимодействия пользователя с React/Redux

Как немедленно обновить компоненты на основе взаимодействия пользователя с React/Redux

27 марта 2022 г.

У вас есть компоненты React. Вы поняли, как использовать Redux для подачи им данных. Вы создаете компонент, который создает/обновляет/удаляет элемент в вашем API, и помещаете его на страницу, отображающую элементы из вашего API. Как заставить всю страницу перезагружаться, чтобы показывать обновленные данные каждый раз, когда пользователь вносит изменения? Состояние Redux и массив зависимостей useEffect().


Можно использовать только React для передачи данных из нашего счетчика в родительский элемент, чтобы получить почти такой же эффект счетчика в моем примере, но использование состояния Redux и массива зависимостей React useEffect() в некоторых отношениях проще, и применимы ко многим другим ситуациям.


В этой статье предполагается базовое знакомство с API, React, Redux и Node. Я начал это приложение с приложения create-реагировать и использую функциональные компоненты и хуки. Вы можете найти весь код в этом репозитории. Я работаю с React (v17.0.1), Redux (v4.0.5), [react-redux] (https://www.npmjs.com/package/react-redux) (v7.2.2) и [redux -thunk] (https://www.npmjs.com/package/redux-thunk) (v2.3.0). В этом примере я использовал [Dog API] (https://dog.ceo/dog-api/documentation/breed), чтобы отображать случайные изображения сиба-ину.


После тестирования конечных точек API (в данном случае в браузере с JSONView) я начал с настройки типов действий и создатели действий для запроса GET API Dog. Я могу создавать асинхронные действия благодаря redux-thunk. Для этого небольшого примера я оставил свои запросы на выборку внутри создателей действий.


Ниже приведены результаты создателя действия с действием загрузки, которое будет важно позже.


```javascript


shibaActions.js


function shibesRequested() { return { type: shibaConstants.SHIBES_REQUESTED } }


функция успеха (результат) { return { тип: shibaConstants.SHIBES_FETCHED, полезная нагрузка: результат } }


сбой функции (ошибка) {возврат {тип: shibaConstants.SHIBE_FETCH_FAIL, полезная нагрузка: ошибка}}


Далее редуктор:


```javascript


shibaReducer.js


константный редуктор = (состояние = начальное состояние, действие) => {


переключатель (действие.тип) {


case shibaConstants.SHIBES_REQUESTED:


вернуть {


...состояние,


shibasLoading: true,


shibasFetched: false


case shibaConstants.SHIBES_FETCHED:


вернуть {


...состояние,


shibasLoading: false,


shibasFetched: true,


Шибас: action.payload


случай shibaConstants.SHIBE_FETCH_FAIL:


вернуть {


...состояние,


shibasLoading: false,


shibasFetched: false


По умолчанию:


возвращаемое состояние


Наконец, я инициализирую хранилище. Первый элемент в composeEnhancers включает [Инструменты разработчика Redux] (https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=en), и эта настройка позволяет использовать как инструменты разработчика, так и промежуточное ПО. (в данном случае редукционный преобразователь).


```javascript


index.js


импортировать {compose, createStore, applyMiddleware} из 'redux';


импортировать {Provider} из 'React-Redux';


импортировать преобразователь из 'redux-thunk';


импортировать редьюсер из './store/shibaReducer';


const rootReducer = редуктор;


const composeEnhancers = window.REDUX_DEVTOOLS_EXTENSION_COMPOSE || сочинять;


const store = createStore (rootReducer, composeEnhancers (applyMiddleware (thunk)));


ReactDOM.render(



<Магазин поставщика={магазин}>


<Приложение />



,


document.getElementById('корень')


К нашим компонентам! Я настроил App.js для отображения изображений Shiba на основе числа в локальном состоянии. Если бы это было настоящее приложение, я бы потратил время на создание уникального ключа и альтернативного текста для каждой картинки.


```javascript


App.js


импорт {connect} из 'реагировать-редукс';


импортировать {shibaActions} из './store/shibaActions';


импортировать счетчик из './components/Counter';


приложение функции (реквизит) {


const [число, setNumber] = useState (1);


использоватьЭффект(() => {


props.fetchShibes(число)


если (!props.shibes || !props.shibes[0]) {


return (

Загружается!

)


} еще {


пусть shibaImages = props.shibes.map (shiba => {


вернуть (


shiba



вернуть (



{shibaImages}


<Счетчик />



const mapStateToProps = (состояние) => {


вернуть {


shibes: гос.шибас


const mapDispatchToProps = (отправка) => {


вернуть {


fetchShibes: (число) => диспетчеризация (shibaActions.fetchShibes (число))


экспортировать подключение по умолчанию (mapStateToProps, mapDispatchToProps) (приложение);


Пустой массив зависимостей useEffect() (скобки после функции) означает, что страница не будет перерисовываться бесконечно, а повторная отрисовка не будет инициирована обновлениями зависимостей компонента.


Примечание. [Денни Скотт] (https://medium.com/better-programming/understanding-the-useeffect-dependency-array-2913da504c44) и команда React не советуют использовать пустые массивы зависимостей, потому что они скрывают ошибки.


Теперь, когда мои шибы отображаются, я запущу компонент счетчика. Поскольку этот API не имеет конечных точек POST, UPDATE или DELETE, счетчик изменит значение num, переданное URL-адресу запроса GET в создателе действия.


```javascript


let url = https://dog.ceo/api/breed/shiba/images/random/${num};


Сначала я обновляю свои типы действий, создателей действий и редюсер. В этом небольшом примере я использую один файл для каждого из них, но обычно у меня есть несколько редюсеров и я использую хук combineReducers().


```javascript


shibaActions.js


функция addOne(число) {


обратная отправка => {


пусть число = число + 1;


отправка (добавить (номер))


функция добавить (число) { вернуть { тип: shibaConstants.ADD_ONE,


полезная нагрузка: число } }


функция subOne (число) {


обратная отправка => {


пусть число = число - 1;


отправка (суб(номер))


function sub(number) { return { type: shibaConstants.SUB_ONE,


полезная нагрузка: число } }


shibaReducer.js


case shibaConstants.ADD_ONE:


вернуть {


...состояние,


счетчик: action.payload


case shibaConstants.SUB_ONE:


вернуть {


...состояние,


счетчик: action.payload


Еще добавляю счетчик в начальное состояние, чтобы всегда было 1 шибэ.


```javascript


shibaReducer.js


const initialState = {shibasLoading: false, shibasFetched: false, counter: 1};


Теперь о самом компоненте счетчика — довольно просто.


```javascript


Счетчик.js


импортировать React из «реагировать»;


импорт {connect} из 'реагировать-редукс';


импортировать {shibaActions} из '../store/shibaActions';


функция Счетчик (реквизит) {


константа handleOnAdd = () => {


реквизит.addOne(реквизит.счетчик)


константа handleOnSub = () => {


реквизит.subOne(реквизит.счетчик)


вернуть (



Счетчик!



{реквизит.счетчик




const mapStateToProps = (состояние) => {


вернуть {


счетчик: состояние.счетчик


const mapDispatchToProps = (отправка) => {


вернуть {


addOne: (число) => диспетчеризация (shibaActions.addOne (число)),


subOne: (число) => отправка (shibaActions.subOne (число))


экспортировать подключение по умолчанию (mapStateToProps, mapDispatchToProps) (счетчик);


Далее, чтобы наша страница перезагружалась каждый раз, когда нажатие кнопки меняет счетчик, нам нужно вернуться к App.js. Мы будем использовать mapStateToProps() для доступа к счетчику в компоненте страницы и передавать его вместо локального состояния number при отправке fetchShibes().


```javascript


App.js


// const [число, setNumber] = useState(1);


использоватьЭффект(() => {


props.fetchShibes(реквизит.счетчик)


}, [реквизит.счетчик]);


Как вы можете видеть выше, единственное, что нам нужно сделать, чтобы страница перезагрузилась с изменениями кнопки, — это поместить состояние счетчика в скобки зависимости useEffect() (команда React советует назначать состояние переменным вместо использования props.state в массиве зависимостей). Добавьте немного стиля, и у нас есть простой маленький счетчик Шиба.


когда пользователь нажимает кнопку + или -, количество изображений шиба на странице изменяется на 1


Заставить страницу перезагружаться на основе асинхронного действия лишь немного сложнее — вы должны использовать состояние загрузки, такое как «shibasLoading» выше. Если вы используете только состояние конечного результата, например shibasFetched, тогда страница будет перезагружаться только на основе первого успешного запроса. Поэтому, если у вас есть пользователь, добавляющий несколько вещей в ваш API, он покажет только первую.


Эта концепция также позволяет создавать сообщения об ошибках в вашем приложении. После добавления объектов состояния shibasFetched и shibasLoading в mapStateToProps() я обновил свой файл App.js.


```javascript


App.js


если (!props.shibes || !props.shibes[0]) {


вернуть (


<дел>


{(props.shibasLoading || !props.shibasFetched) && <h1


className="heading">Загружается!}


{!props.shibasLoading && !props.shibasFetched &&


Что-то пошло не так - не загружаются шибы.

}



} еще {


пусть shibaImages = props.shibes.map (shiba => {


вернуть (


shiba



вернуть (



{!props.shibasLoading && !props.shibasFetched &&


Что-то пошло не так - не загружаются шибы.

}


<Счетчик />


{shibaImages}



Используя условную логику JSX и наше состояние Redux, мы можем отображать различные сообщения об ошибках в зависимости от состояния наших асинхронных запросов.


Заключение


После того, как я изо всех сил пытался понять это самостоятельно, я попытался создать простой пример того, как использовать хук useEffect() для перезагрузки компонентов на основе изменений, которые вносят другие компоненты.


Есть много способов использовать это в приложении, и сама базовая концепция позволяет вам делать забавные вещи, такие как настраиваемые сообщения об ошибках, используя условную логику JSX.


Если это помогло вам, когда вы застряли или оставили вас с вопросом, оставьте мне комментарий!


Также опубликовано здесь



Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE