Как немедленно обновить компоненты на основе взаимодействия пользователя с 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 => {
вернуть (
вернуть (
{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
в массиве зависимостей). Добавьте немного стиля, и у нас есть простой маленький счетчик Шиба.
Заставить страницу перезагружаться на основе асинхронного действия лишь немного сложнее — вы должны использовать состояние загрузки, такое как «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 => {
вернуть (
вернуть (
{!props.shibasLoading && !props.shibasFetched &&
Что-то пошло не так - не загружаются шибы.
}
<Счетчик />
{shibaImages}
Используя условную логику JSX и наше состояние Redux, мы можем отображать различные сообщения об ошибках в зависимости от состояния наших асинхронных запросов.
Заключение
После того, как я изо всех сил пытался понять это самостоятельно, я попытался создать простой пример того, как использовать хук useEffect()
для перезагрузки компонентов на основе изменений, которые вносят другие компоненты.
Есть много способов использовать это в приложении, и сама базовая концепция позволяет вам делать забавные вещи, такие как настраиваемые сообщения об ошибках, используя условную логику JSX.
Если это помогло вам, когда вы застряли или оставили вас с вопросом, оставьте мне комментарий!
Также опубликовано здесь
Оригинал