StargateBasic
Чему мы научимся
Мы узнаем как создать store, как получить доступ к состоянию и как обновлять его.
Установка
Для установки репозитория проекта необходимо ввести в консоль:
git clone https://github.com/gHashTag/stargate1.git
Далее в папке проекта:
yarn // либо используем npm install
И потом:
npx react-native run-android // или run-ios
После этих шагов вы должны получить такой результат:
Обзор
Рассмотрим папку src/store/movieSlice
:
import { createSlice } from '@reduxjs/toolkit'
import { nanoid } from 'nanoid/non-secure'
import DATA from './data.json'
const initialState = {
data: DATA
}
export const movieSlice = createSlice({
name: 'movie',
initialState,
reducers: {
createNew: (state, action) => {
state.data.push({ ...action.payload, id: nanoid() })
},
removeById: (state, action) => {
state.data = state.data.filter(a => a.id !== action.payload)
}
}
})
export const { createNew, removeById } = movieSlice.actions
export const movieReducer = movieSlice.reducer
Тут создается "Срез" нашего хранилища, там мы указываем его название, первоначальное состояние, и функции-редьюсеры для изменения состояния. После экспортируем наш movieSlice, reducer и actions из среза для дальнейшего использования.
После этого мы должны создать наш Store и обернуть приложение в <Provider>
для того чтобы приложение имело доступ к состоянию →
import { configureStore } from '@reduxjs/toolkit'
import { movieReducer } from './movieSlice'
export const store = configureStore({
reducer: {
movie: movieReducer
}
})
import React from 'react'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { Provider } from 'react-redux'
import Navigation from './src/Navigation'
import { store } from './src/store'
function App() {
return (
<Provider store={store}>
<SafeAreaProvider>
<Navigation />
</SafeAreaProvider>
</Provider>
)
}
export default App
Готово! Теперь мы можем получить состояние из store в любом месте приложения.
Доступ к состоянию
Теперь давайте используем состояние в src/screens/HomeScreen
:
// ...другие импорты
import { useSelector } from 'react-redux'
export function HomeScreen({ navigation }) {
{/* ... */}
const list = useSelector(state => state.movie.data).filter(a =>
a.name.toLowerCase().includes(filterText.toLowerCase())
)
{/* ... */}
return (
<SafeAreaView>
{/*.....*/}
<FlatList
data={list}
{/*.....*/}
keyExtractor={item => nanoid()}
showsVerticalScrollIndicator={false}
renderItem={({ item, index }) => (
<ImageCard
data={item}
onPress={() => navigation.navigate('DETAIL_SCREEN', { show: item })}
/>
)}
/>
</SafeAreaView>
)
}
Как мы видим нужно использовать useSelector хук из библиотеки react-redux для доступа к любому состоянию в компонентах.
Изменение состояния
Единственный способ обновить состояние — вызвать dispatch()
метод, который возвращает хук useDispatch()
и передать объект действия. Хранилище запустит свою функцию редуктора и сохранит новое значение состояния внутри.
Мы ранее определили редьюсеры в src/store/movieSlice
, что же давайте их используем.
Удаление
Я реализовал удаление кино-карточки в src/components/ImageCard
через Alert:
import React from 'react'
import { useDispatch } from 'react-redux'
import { W } from '../../constants'
import { removeById } from '../../store/movieSlice'
const ImageCard = ({ data, onPress }) => {
const dispatch = useDispatch()
function openAlert() {
function del() {
dispatch(removeById(id))
}
Alert.alert(
'Confirm action',
'Are you sure you want to delete this movie?',
[
{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel'
},
{ text: 'Yes', onPress: del }
],
{ cancelable: true }
)
}
return // Component
}
Как мы видим, в функцию dispatch
передаются действия(actions), а действие в свою очередь может принимать payload аргумент(в данном случае id).
Добавление
Добавление в состояние аналогично. (src/screens/AddMovieScreen):
import React from 'react'
import { StyleSheet, View, ScrollView, KeyboardAvoidingView } from 'react-native'
import { FormMovie, Header } from '../../components'
import { BLUE, WHITE } from '../../constants'
import { useHeaderHeight } from '@react-navigation/elements'
import { useDispatch } from 'react-redux'
import { createNew } from '../../store/movieSlice'
export function AddMovieScreen({ navigation }) {
const headerHeight = useHeaderHeight()
const dispatch = useDispatch()
function handleSubmit(form) {
dispatch(createNew(form)) // передаем payload
navigation.navigate('HOME_SCREEN')
}
return (
<>
<Header
title={'Your movie'}
onPress={() => navigation.goBack()}
iconLeft="ios-arrow-back"
headerColor={BLUE}
colorLeft={WHITE}
/>
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={headerHeight}
>
<ScrollView>
<View style={screenCont}>
<View style={{ height: 50 }} />
<FormMovie onSubmit={handleSubmit} />
</View>
<View style={{ height: 70 }} />
</ScrollView>
</KeyboardAvoidingView>
</>
)
}
Итог
Мы узнали как использовать redux на практике!