react-native + DVA + react-native-snap-carousel【轮播图】
- 安装
yarn add react-native-snap-carousel
yarn add @types/react-native-snap-carousel -D
// DVA的使用
// src/config/dva.ts
import { create } from 'dva-core-ts'
import createLoading from 'dva-loading-ts'
import models from '@/models/index'
const app = create({
onError(err) {
console.log(err)
},
})
models.forEach((model) => {
app.model(model)
})
app.use(createLoading())
app.start()
export default app._store
// src/index.tsx
import React from 'react'
import Navigator from './navigator'
import { Provider } from 'react-redux'
import store from '@/config/dva'
import { StatusBar } from 'react-native'
import '@/config/http'
export default class extends React.Component {
render() {
return (
<Provider store={store}>
{/* 顶部状态栏组件 */}
<StatusBar
backgroundColor="transparent"
barStyle="dark-content"
translucent
/>
<Navigator />
</Provider>
)
}
}
// modal 层
// index.ts
import home from './home'
import { DvaLoadingState } from 'dva-loading-ts'
const models = [home, category, albumModel]
export type RootState = {
home: typeof home.state
loading: DvaLoadingState
}
export default models
// cateory.ts
import { Model, Effect } from 'dva-core-ts'
import { Reducer } from 'redux'
import axios from 'axios'
import { RootState } from './index'
// 轮播图
const CAROUSEL_URL = '/mock/20/carousel'
export interface ICarousel {
id: string
image: string
colors: [string, string]
}
export interface HomeState {
carousels: ICarousel[]
activeCarouseIndex: number // 当前轮播图的下标
}
interface HomeModel extends Model {
namespace: 'home'
state: HomeState
reducers: {
setState: Reducer<HomeState>
}
effects: {
fetchCarousels: Effect
}
}
const initialState: HomeState = {
carousels: [],
activeCarouseIndex: 0,
}
const homeModel: HomeModel = {
namespace: 'home',
state: initialState,
reducers: {
setState(state = initialState, { payload }) {
return {
...state,
...payload,
}
},
},
effects: {
*fetchCarousels(_, { call, put }) {
const { data } = yield call(axios.get, CAROUSEL_URL)
yield put({
type: 'setState',
payload: {
carousels: data,
},
})
},
},
}
export default homeModel
// view层
import React from 'react'
import { View, StyleSheet } from 'react-native'
import SnapCarousel, {
ParallaxImage,
Pagination,
AdditionalParallaxProps
} from 'react-native-snap-carousel'
import { ICarousel } from 'models/home'
import { viewportWidth, wp, hp } from '@/utils/index'
import { connect, ConnectedProps } from 'react-redux'
import { RootState } from '@/models/index'
const sliderWidth = viewportWidth
const sideWidth = wp(90)
export const sideHeight = hp(26)
const itemWidth = sideWidth + wp(2) * 2
const mapStateToProps = ({ home }: RootState) => ({
data: home.carousels,
activeCarouseIndex: home.activeCarouseIndex,
})
const connector = connect(mapStateToProps)
type ModelState = ConnectedProps<typeof connector>
interface IProps extends ModelState {
}
class Carousel extends React.Component<IProps> {
onSnapToItem = (index: number) => {
const { dispatch } = this.props
dispatch({
type: 'home/setState',
payload: {
activeCarouseIndex: index,
}
})
}
renderItem = ({ item }: { item: ICarousel }, parallaxProps?: AdditionalParallaxProps) => {
return (
<ParallaxImage
source={{ uri: item.image }}
style={styles.image}
containerStyle={styles.imageContainer}
parallaxFactor={0.8} // 视察参数
showSpinner
spinnerColor="rgba(0, 0, 0, 0.25)"
{...parallaxProps}
/>
)
}
get pagination() {
const { data, activeCarouseIndex } = this.props
return (
<View style={styles.paginationWrapper}>
<Pagination
containerStyle={styles.paginationContainer}
dotContainerStyle={styles.dotContainer}
dotStyle={styles.dot}
activeDotIndex={activeCarouseIndex}
dotsLength={data.length}
inactiveDotScale={0.7}
inactiveDotOpacity={0.4}
/>
</View>
)
}
render() {
const { data } = this.props
return (
<View>
<SnapCarousel
data={data}
renderItem={this.renderItem}
sliderWidth={sliderWidth}
itemWidth={itemWidth}
hasParallaxImages
onSnapToItem={this.onSnapToItem}
loop
autoplay
/>
{this.pagination}
</View>
)
}
}
const styles = StyleSheet.create({
imageContainer: {
width: itemWidth,
height: sideHeight,
borderRadius: 8,
},
image: {
...StyleSheet.absoluteFillObject,
resizeMode: 'cover',
},
paginationWrapper: {
justifyContent: 'center',
alignItems: 'center',
},
paginationContainer: {
position: 'absolute',
top: -20,
backgroundColor: 'rgba(0, 0, 0, 0.35)',
paddingHorizontal: 3,
paddingVertical: 4,
borderRadius: 8,
},
dotContainer: {
marginHorizontal: 6,
},
dot: {
width: 6,
height: 6,
borderRadius: 3,
backgroundColor: 'rgba(255, 255, 255, 0.92)'
}
})
export default connector(Carousel)