Authored by 王钱钧

添加个人中心逻辑代码。code review by 于良

... ... @@ -45,8 +45,8 @@ let VERSION = '0.0.1';
function getInitialState() {
const _initState = {
home: (new homeInitialState()),
user: (new userInitialState()),
posting: (new postingInitialState()),
user: (new userInitialState()),
};
return _initState;
}
... ...
import React, { Component } from 'react';
import {
Animated,
Dimensions,
ScrollView,
StyleSheet,
View
} from 'react-native';
const { bool, func, number, string } = React.PropTypes;
const window = Dimensions.get('window');
const SCROLLVIEW_REF = 'ScrollView';
const pivotPoint = (a, b) => (a - b);
const renderEmpty = () => <View/>;
// Override `toJSON` of interpolated value because of
// an error when serializing style on view inside inspector.
// See: https://github.com/jaysoo/react-native-parallax-scroll-view/issues/23
const interpolate = (value, opts) => {
const x = value.interpolate(opts);
x.toJSON = () => x.__getValue();
return x;
};
// Properties accepted by `ParallaxScrollView`.
const IPropTypes = {
backgroundColor: string,
backgroundScrollSpeed: number,
fadeOutForeground: bool,
fadeOutBackground: bool,
contentBackgroundColor: string,
onChangeHeaderVisibility: func,
parallaxHeaderHeight: number.isRequired,
renderBackground: func,
renderFixedHeader: func,
renderForeground: func,
renderScrollComponent: func,
renderStickyHeader: func,
stickyHeaderHeight: number,
contentContainerStyle: View.propTypes.style
};
class ParallaxScrollView extends Component {
constructor(props) {
super(props);
if (props.renderStickyHeader && !props.stickyHeaderHeight) {
console.warn('Property `stickyHeaderHeight` must be set if `renderStickyHeader` is used.');
}
if (props.renderParallaxHeader !== renderEmpty && !props.renderForeground) {
console.warn('Property `renderParallaxHeader` is deprecated. Use `renderForeground` instead.');
}
this.state = {
scrollY: new Animated.Value(0),
viewHeight: window.height,
viewWidth: window.width
};
this._footerComponent = { setNativeProps() {} }; // Initial stub
this._footerHeight = 0;
}
render() {
const {
backgroundColor,
backgroundScrollSpeed,
children,
contentBackgroundColor,
fadeOutForeground,
fadeOutBackground,
parallaxHeaderHeight,
renderBackground,
renderFixedHeader,
renderForeground,
renderParallaxHeader,
renderScrollComponent,
renderStickyHeader,
stickyHeaderHeight,
style,
contentContainerStyle,
...scrollViewProps
} = this.props;
const background = this._renderBackground({ fadeOutBackground, backgroundScrollSpeed, backgroundColor, parallaxHeaderHeight, stickyHeaderHeight, renderBackground });
const foreground = this._renderForeground({ fadeOutForeground, parallaxHeaderHeight, stickyHeaderHeight, renderForeground: renderForeground || renderParallaxHeader });
const bodyComponent = this._wrapChildren(children, { contentBackgroundColor, stickyHeaderHeight, contentContainerStyle });
const footerSpacer = this._renderFooterSpacer({ contentBackgroundColor });
const maybeStickyHeader = this._maybeRenderStickyHeader({ parallaxHeaderHeight, stickyHeaderHeight, backgroundColor, renderFixedHeader, renderStickyHeader });
const scrollElement = renderScrollComponent(scrollViewProps);
return (
<View style={[style, styles.container]}
onLayout={(e) => this._maybeUpdateViewDimensions(e)}>
{ background }
{
React.cloneElement(scrollElement, {
ref: SCROLLVIEW_REF,
style: [styles.scrollView, scrollElement.props.style],
scrollEventThrottle: 16,
onScroll: this._onScroll.bind(this),
},
foreground,
bodyComponent,
footerSpacer
)
}
{ maybeStickyHeader }
</View>
);
}
/*
* Expose `ScrollView` API so this component is composable with any component that expects a `ScrollView`.
*/
getScrollResponder() {
return this.refs[SCROLLVIEW_REF].getScrollResponder();
}
getScrollableNode() {
return this.getScrollResponder().getScrollableNode();
}
getInnerViewNode() {
return this.getScrollResponder().getInnerViewNode();
}
scrollTo(...args) {
this.getScrollResponder().scrollTo(...args);
}
setNativeProps(props) {
this.refs[SCROLLVIEW_REF].setNativeProps(props);
}
/*
* Private helpers
*/
_onScroll(e) {
const {
parallaxHeaderHeight,
stickyHeaderHeight,
onChangeHeaderVisibility,
onScroll: prevOnScroll = () => {}
} = this.props;
const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);
this._maybeUpdateScrollPosition(e);
if (e.nativeEvent.contentOffset.y >= p) {
onChangeHeaderVisibility(false);
} else {
onChangeHeaderVisibility(true);
}
prevOnScroll(e);
}
// This optimizes the state update of current scrollY since we don't need to
// perform any updates when user has scrolled past the pivot point.
_maybeUpdateScrollPosition(e) {
const { parallaxHeaderHeight, stickyHeaderHeight } = this.props;
const { scrollY } = this.state;
const { nativeEvent: { contentOffset: { y: offsetY } } } = e;
const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);
if (offsetY <= p || scrollY._value <= p) {
scrollY.setValue(offsetY);
}
}
_maybeUpdateViewDimensions(e) {
const { nativeEvent: { layout: { width, height} } } = e;
if (width !== this.state.viewWidth || height !== this.state.viewHeight) {
this.setState({
viewWidth: width,
viewHeight: height
});
}
}
_renderBackground({ fadeOutBackground, backgroundScrollSpeed, backgroundColor, parallaxHeaderHeight, stickyHeaderHeight, renderBackground }) {
const { viewWidth, viewHeight, scrollY } = this.state;
const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);
return (
<Animated.View
style={[styles.backgroundImage, {
backgroundColor: backgroundColor,
height: parallaxHeaderHeight,
width: viewWidth,
opacity: fadeOutBackground
? interpolate(scrollY, {
inputRange: [0, p * (1/2), p * (3/4), p],
outputRange: [1, 0.3, 0.1, 0],
extrapolate: 'clamp'
})
: 1,
transform: [{
translateY: interpolate(scrollY, {
inputRange: [0, p],
outputRange: [0, -(p / backgroundScrollSpeed)],
extrapolateRight: 'extend',
extrapolateLeft: 'clamp'
})
}, {
scale: interpolate(scrollY, {
inputRange: [-viewHeight, 0],
outputRange: [5, 1],
extrapolate: 'clamp'
})
}]
}]}>
<View>
{ renderBackground() }
</View>
</Animated.View>
);
}
_renderForeground({ fadeOutForeground, parallaxHeaderHeight, stickyHeaderHeight, renderForeground }) {
const { scrollY } = this.state;
const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);
return (
<View style={styles.parallaxHeaderContainer}>
<Animated.View
style={[styles.parallaxHeader, {
height: parallaxHeaderHeight,
opacity: fadeOutForeground
? interpolate(scrollY, {
inputRange: [0, p * (1/2), p * (3/4), p],
outputRange: [1, 0.3, 0.1, 0],
extrapolate: 'clamp'
})
: 1
}]}>
<View style={{ height: parallaxHeaderHeight }}>
{ renderForeground() }
</View>
</Animated.View>
</View>
);
}
_wrapChildren(children, { contentBackgroundColor, stickyHeaderHeight, contentContainerStyle }) {
const { viewHeight } = this.state;
const containerStyles = [{backgroundColor: contentBackgroundColor}];
if(contentContainerStyle)
containerStyles.push(contentContainerStyle);
return (
<View
style={containerStyles}
onLayout={e => {
// Adjust the bottom height so we can scroll the parallax header all the way up.
const { nativeEvent: { layout: { height } } } = e;
const footerHeight = Math.max(0, viewHeight - height - stickyHeaderHeight);
if (this._footerHeight !== footerHeight) {
this._footerComponent.setNativeProps({ style: { height: footerHeight }});
this._footerHeight = footerHeight;
}
}}>
{ children }
</View>
);
}
_renderFooterSpacer({ contentBackgroundColor }) {
return (
<View ref={ref => this._footerComponent = ref } style={{ backgroundColor: contentBackgroundColor }}/>
);
}
_maybeRenderStickyHeader({ parallaxHeaderHeight, stickyHeaderHeight, backgroundColor, renderFixedHeader, renderStickyHeader }) {
const { viewWidth, scrollY } = this.state;
if (renderStickyHeader || renderFixedHeader) {
const p = pivotPoint(parallaxHeaderHeight, stickyHeaderHeight);
return (
<View style={[styles.stickyHeader, { width: viewWidth, ...(stickyHeaderHeight ? { height: stickyHeaderHeight } : null ) }]}>
{
renderStickyHeader
? (
<Animated.View
style={{
backgroundColor: backgroundColor,
height: stickyHeaderHeight,
opacity: interpolate(scrollY, {
inputRange: [0, p],
outputRange: [0, 1],
extrapolate: 'clamp'
})
}}>
<Animated.View
style={{
transform: [{
translateY: interpolate(scrollY, {
inputRange: [0, p],
outputRange: [stickyHeaderHeight, 0],
extrapolate: 'clamp'
})
}]
}}>
{ renderStickyHeader() }
</Animated.View>
</Animated.View>
)
: null
}
{ renderFixedHeader && renderFixedHeader() }
</View>
);
} else {
return null;
}
}
}
ParallaxScrollView.propTypes = IPropTypes;
ParallaxScrollView.defaultProps = {
backgroundScrollSpeed: 5,
backgroundColor: '#000',
contentBackgroundColor: '#fff',
fadeOutForeground: true,
onChangeHeaderVisibility: () => {},
renderScrollComponent: props => <ScrollView {...props}/>,
renderBackground: renderEmpty,
renderParallaxHeader: renderEmpty, // Deprecated (will be removed in 0.18.0)
renderForeground: null,
stickyHeaderHeight: 0,
contentContainerStyle: null
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'transparent'
},
parallaxHeaderContainer: {
backgroundColor: 'transparent',
overflow: 'hidden'
},
parallaxHeader: {
backgroundColor: 'transparent',
overflow: 'hidden'
},
backgroundImage: {
position: 'absolute',
backgroundColor: 'transparent',
overflow: 'hidden',
top: 0
},
stickyHeader: {
backgroundColor: 'transparent',
position: 'absolute',
overflow: 'hidden',
top: 0,
left: 0
},
scrollView: {
backgroundColor: 'transparent'
}
});
module.exports = ParallaxScrollView;
... ...
'use strict';
var React = require('react');
var ReactNative = require('react-native');
var {
Dimensions,
StyleSheet,
View,
ScrollView,
Animated,
} = ReactNative;
/**
* BlurView temporarily removed until semver stuff is set up properly
*/
//var BlurView /* = require('react-native-blur').BlurView */;
var ScrollableMixin = require('react-native-scrollable-mixin');
var screen = Dimensions.get('window');
var ScrollViewPropTypes = ScrollView.propTypes;
var ParallaxView = React.createClass({
mixins: [ScrollableMixin],
propTypes: {
...ScrollViewPropTypes,
windowHeight: React.PropTypes.number,
backgroundSource: React.PropTypes.object,
header: React.PropTypes.node,
blur: React.PropTypes.string,
contentInset: React.PropTypes.object,
},
getDefaultProps: function () {
return {
windowHeight: 300,
contentInset: {
top: screen.scale
}
};
},
getInitialState: function () {
return {
scrollY: new Animated.Value(0)
};
},
/**
* IMPORTANT: You must return the scroll responder of the underlying
* scrollable component from getScrollResponder() when using ScrollableMixin.
*/
getScrollResponder() {
return this._scrollView.getScrollResponder();
},
setNativeProps(props) {
this._scrollView.setNativeProps(props);
},
renderBackground: function () {
var { windowHeight, backgroundSource, blur } = this.props;
var { scrollY } = this.state;
if (!windowHeight || !backgroundSource) {
return null;
}
return (
<Animated.Image
style={[styles.background, {
height: windowHeight,
transform: [{
translateY: scrollY.interpolate({
inputRange: [ -windowHeight, 0, windowHeight],
outputRange: [windowHeight/2, 0, -windowHeight/3]
})
},{
scale: scrollY.interpolate({
inputRange: [ -windowHeight, 0, windowHeight],
outputRange: [2, 1, 1]
})
}]
}]}
source={backgroundSource}>
{/*
!!blur && (BlurView || (BlurView = require('react-native-blur').BlurView)) &&
<BlurView blurType={blur} style={styles.blur} />
*/}
</Animated.Image>
);
},
renderHeader: function () {
var { windowHeight, backgroundSource } = this.props;
var { scrollY } = this.state;
if (!windowHeight || !backgroundSource) {
return null;
}
return (
<Animated.View style={{
position: 'relative',
height: windowHeight,
opacity: scrollY.interpolate({
inputRange: [-windowHeight, 0, windowHeight / 1.2],
outputRange: [1, 1, 0]
}),
}}>
{this.props.header}
</Animated.View>
);
},
render: function () {
var { style, ...props } = this.props;
return (
<View style={[styles.container, style]}>
{this.renderBackground()}
<ScrollView
ref={component => { this._scrollView = component; }}
{...props}
style={styles.scrollView}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.scrollY }}}]
)}
scrollEventThrottle={16}>
{this.renderHeader()}
<View style={[styles.content, props.scrollableViewStyle]}>
{this.props.children}
</View>
</ScrollView>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
borderColor: 'transparent',
},
scrollView: {
backgroundColor: 'transparent',
},
background: {
position: 'absolute',
backgroundColor: '#2e2f31',
width: screen.width,
resizeMode: 'cover'
},
blur: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
backgroundColor: 'transparent',
},
content: {
shadowColor: '#222',
shadowOpacity: 0.3,
shadowRadius: 2,
backgroundColor: '#fff',
flex: 1,
flexDirection: 'column'
}
});
module.exports = ParallaxView;
... ...
... ... @@ -2,9 +2,12 @@
import React from 'react';
import ReactNative from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view';
import ImmutablePropTypes from 'react-immutable-proptypes';
import UserCenterTop from './user/UserCenterTop';
import ScrollableTabView from 'react-native-scrollable-tab-view';
import CommunityList from './CommonComp/CommunityList';
import ParallaxView from './CommonComp/ParallaxView';
const {
... ... @@ -13,24 +16,115 @@ const {
ScrollView,
Platform,
Dimensions,
StyleSheet
StyleSheet,
PanResponder,
} = ReactNative;
export default class User extends React.Component {
static propTypes = {
dataBlob: React.PropTypes.shape({
userInfo: React.PropTypes.shape({
userInfo: ImmutablePropTypes.listOf(
ImmutablePropTypes.contains({
avatar: React.PropTypes.string,
bgImage:React.PropTypes.string,
userName:React.PropTypes.string.isRequired,
sign: React.PropTypes.string,
}),
),
}),
posts: React.PropTypes.arrayOf(
ImmutablePropTypes.contains({
avatar: React.PropTypes.string.isRequired,
name: React.PropTypes.string.isRequired,
timeago: React.PropTypes.string.isRequired,
isOwner: React.PropTypes.bool,
isTop: React.PropTypes.bool,
isLike: React.PropTypes.bool,
title: React.PropTypes.string,
desc: React.PropTypes.string,
thumbs: ImmutablePropTypes.listOf(
ImmutablePropTypes.contains({
url: React.PropTypes.string,
})
),
section: React.PropTypes.string,
commentCount: React.PropTypes.number,
likeCount: React.PropTypes.number,
}),
),
}),
onPressAvatar: React.PropTypes.func,
onPressComment: React.PropTypes.func,
onPressLike: React.PropTypes.func,
};
constructor(props) {
super (props);
}
render() {
return (
<View style={styles.container}>
<View style={styles.container}>
<UserCenterTop/>
<ScrollableTabView style={styles.bottom}>
<Text tabLabel="React" />
<Text tabLabel="Flow" />
<Text tabLabel="Jest" />
<CommunityList
bounces={false}
tabLabel="我的帖子"
jsonData={this.props.dataBlob.posts}
onPressAvatar={(url) => {
this.props.onPressAvatar && this.props.onPressAvatar(url);
}}
onPressComment={(url) => {
this.props.onPressComment && this.props.onPressComment(url);
}}
onPressLike={(url) => {
this.props.onPressLike && this.props.onPressLike(url);
}}
/>
<CommunityList
tabLabel="我赞过的"
jsonData={this.props.dataBlob.posts}
onPressAvatar={(url) => {
this.props.onPressAvatar && this.props.onPressAvatar(url);
}}
onPressComment={(url) => {
this.props.onPressComment && this.props.onPressComment(url);
}}
onPressLike={(url) => {
this.props.onPressLike && this.props.onPressLike(url);
}}
/>
<CommunityList
tabLabel="我的回复"
jsonData={this.props.dataBlob.posts}
onPressAvatar={(url) => {
this.props.onPressAvatar && this.props.onPressAvatar(url);
}}
onPressComment={(url) => {
this.props.onPressComment && this.props.onPressComment(url);
}}
onPressLike={(url) => {
this.props.onPressLike && this.props.onPressLike(url);
}}
/>
</ScrollableTabView>
</View>
)
}
}
... ... @@ -44,6 +138,7 @@ let styles = StyleSheet.create({
top: 0,
height: height,
backgroundColor: 'transparent',
// backgroundColor: 'red',
// flexDirection: 'column',
// justifyContent: 'center',
},
... ...
... ... @@ -10,9 +10,9 @@ export default keyMirror({
USER_BACKGROUND_TAP: null,
USER_AVATAR_TAP:null,
USER_POST_REQUEST: null, //我的帖子
USER_POST_SUCCESS: null,
USER_POST_FAILURE: null,
USER_POSTS_REQUEST: null, //我的帖子
USER_POSTS_SUCCESS: null,
USER_POSTS_FAILURE: null,
USER_LIKE_REQUEST: null, //我赞过的
USER_LIKE_SUCCESS: null,
... ...
... ... @@ -14,7 +14,6 @@ import * as homeActions from '../reducers/home/homeActions';
import {Actions} from 'react-native-router-flux';
import {Actions} from 'react-native-router-flux';
const {
... ...
... ... @@ -2,12 +2,12 @@
import React from 'react';
import ReactNative from 'react-native';
import Immutable, {Map} from 'immutable';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {Map} from 'immutable';
import User from '../components/User';
import * as userActions from '../reducers/user/userActions';
... ... @@ -46,15 +46,149 @@ function mapDispatchToProps(dispatch) {
class UserContainer extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
this._fetchData();
}
componentWillMount() {
}
_onPressAvatar(url) {
console.log('avatar');
}
_onPressComment(url) {
console.log('comment');
}
_onPressLike(url) {
console.log('like');
}
render() {
let userInfo = {
avatar: require('../images/avatar-default.png'),
userName:'Arthur',
sign:'Hello, Bro',
bgImage: require('../images/user-bg.png'),
};
let posts = [
{
avatar: 'https://img11.static.yhbimg.com/yhb-img01/2016/06/28/11/01f429fffdff555ed0c141a5ec2b4fd421.jpg?imageView2/2/w/640/h/240',
name: '余文乐',
timeago: '2小时前',
isOwner: false,
isTop: true,
isLike: true,
title: 'Yoho!Buy特邀摄影师大赛开始报名啦!',
desc: 'MADNESS作为“六叔”余文乐的个人品牌,经过几个季度的产品表现,相信大家都知道这并不是玩票性质,而是余文乐在做心中的街头品牌。此番MADNESS正式迎来2016春夏的开季,以Los Angeles作为拍摄地点,延续余文乐一直喜欢的简约风格',
thumbs: [
{
url: 'https://img11.static.yhbimg.com/yhb-img01/2016/06/28/11/01f429fffdff555ed0c141a5ec2b4fd421.jpg?imageView2/2/w/640/h/240',
},
{
url: 'https://img11.static.yhbimg.com/yhb-img01/2016/06/28/11/01f429fffdff555ed0c141a5ec2b4fd421.jpg?imageView2/2/w/640/h/240',
},
{
url: 'https://img11.static.yhbimg.com/yhb-img01/2016/06/28/11/01f429fffdff555ed0c141a5ec2b4fd421.jpg?imageView2/2/w/640/h/240',
}
],
section: '永恒的潮流',
commentCount: 123,
likeCount: 45678,
url: 'https://www.baidu.com'
},
{
avatar: 'https://img11.static.yhbimg.com/yhb-img01/2016/06/28/11/01f429fffdff555ed0c141a5ec2b4fd421.jpg?imageView2/2/w/640/h/240',
name: '余文乐',
timeago: '2小时前',
isOwner: true,
isTop: false,
isLike: false,
title: 'Yoho!Buy特邀摄影师大赛开始报名啦!',
desc: 'MADNESS作为“六叔”余文乐的个人品牌,经过几个季度的产品表现,相信大家都知道这并不是玩票性质,而是余文乐在做心中的街头品牌。此番MADNESS正式迎来2016春夏的开季,以Los Angeles作为拍摄地点,延续余文乐一直喜欢的简约风格',
thumbs: [
{
url: 'https://img11.static.yhbimg.com/yhb-img01/2016/06/28/11/01f429fffdff555ed0c141a5ec2b4fd421.jpg?imageView2/2/w/640/h/240',
},
{
url: 'https://img11.static.yhbimg.com/yhb-img01/2016/06/28/11/01f429fffdff555ed0c141a5ec2b4fd421.jpg?imageView2/2/w/640/h/240',
},
{
url: 'https://img11.static.yhbimg.com/yhb-img01/2016/06/28/11/01f429fffdff555ed0c141a5ec2b4fd421.jpg?imageView2/2/w/640/h/240',
}
],
section: '永恒的潮流',
commentCount: 123,
likeCount: 45678,
url: 'https://www.baidu.com'
},
{
avatar: 'https://img11.static.yhbimg.com/yhb-img01/2016/06/28/11/01f429fffdff555ed0c141a5ec2b4fd421.jpg?imageView2/2/w/640/h/240',
name: '余文乐',
timeago: '2小时前',
isOwner: false,
isTop: false,
isLike: true,
title: 'Yoho!Buy特邀摄影师大赛开始报名啦!',
desc: 'MADNESS作为“六叔”余文乐的个人品牌,经过几个季度的产品表现,相信大家都知道这并不是玩票性质,而是余文乐在做心中的街头品牌。此番MADNESS正式迎来2016春夏的开季,以Los Angeles作为拍摄地点,延续余文乐一直喜欢的简约风格',
thumbs: [
{
url: 'https://img11.static.yhbimg.com/yhb-img01/2016/06/28/11/01f429fffdff555ed0c141a5ec2b4fd421.jpg?imageView2/2/w/640/h/240',
},
{
url: 'https://img11.static.yhbimg.com/yhb-img01/2016/06/28/11/01f429fffdff555ed0c141a5ec2b4fd421.jpg?imageView2/2/w/640/h/240',
},
{
url: 'https://img11.static.yhbimg.com/yhb-img01/2016/06/28/11/01f429fffdff555ed0c141a5ec2b4fd421.jpg?imageView2/2/w/640/h/240',
}
],
section: '永恒的潮流',
commentCount: 123,
likeCount: 45678,
url: 'https://www.baidu.com'
},
];
let dataBlob = {
userInfo: Immutable.fromJS(userInfo).toObject(),
// notice: Immutable.fromJS(notice).toObject(),
// section: Immutable.fromJS(section).toObject(),
posts: Immutable.fromJS(posts).toArray(),
};
return (
<View style={styles.container}>
<User/>
<StatusBar
hidden={false}
barStyle={'light-content'}
/>
<User
dataBlob={dataBlob}
onPressAvatar={this._onPressAvatar}
onPressComment={this._onPressComment}
onPressLike={this._onPressLike}
/>
</View>
);
}
// private method
_fetchData() {
// this.props.actions.userInfo();
// this.props.actions.posts();
}
}
let {width, height} = Dimensions.get('window');
... ...
... ... @@ -26,11 +26,8 @@ import { combineReducers } from 'redux';
*/
const rootReducer = combineReducers({
home,
<<<<<<< HEAD
user,
=======
posting,
>>>>>>> ed57ea2be169d48b2d4344fc07b9ee3be6f45db5
user,
});
export default rootReducer;
... ...
... ... @@ -6,9 +6,9 @@ import UserService from '../../services/UserService';
const {
USER_POST_REQUEST,
USER_POST_SUCCESS,
USER_POST_FAILURE,
USER_POSTS_REQUEST,
USER_POSTS_SUCCESS,
USER_POSTS_FAILURE,
USER_LIKE_REQUEST,
USER_LIKE_SUCCESS,
... ... @@ -22,20 +22,20 @@ const {
export function postRequest() {
return {
type: USER_POST_REQUEST
type: USER_POSTS_REQUEST
};
}
export function postSuccess(json) {
return {
type: USER_POST_SUCCESS,
type: USER_POSTS_SUCCESS,
payload: json
};
}
export function postFailure(error) {
return {
type: USER_POST_FAILURE,
type: USER_POSTS_FAILURE,
payload: error
};
}
... ... @@ -79,17 +79,31 @@ export function replyFailure(error) {
payload: error
};
}
export function userInfo() {
// return dispatch => {
// dispatch(postRequest());
// return new UserService().posts()
// .then(json => {
// dispatch(postSuccess(json))
// })
// .catch(error => {
// dispatch(postFailure(error));
// });
// };
}
// 获取【我的帖子】数据
export function posts() {
return dispatch => {
dispatch(postRequest());
return new UserService().posts()
.then(json => {
dispatch(postSuccess(json))
})
.catch(error => {
dispatch(postFailure(error));
});
// dispatch(postRequest());
// return new UserService().posts()
// .then(json => {
dispatch(postSuccess(postsTestData));
// })
// .catch(error => {
// dispatch(postFailure(error));
// });
};
}
... ... @@ -120,3 +134,44 @@ export function reply() {
});
};
}
//测试数据
let postsTestData = {
sum: '100',
currentPage: 1,
pageCount: 1,
list: [
{
name: 'Arthur',
title: '这是一篇文章',
brief: '简介',
topic: '复古市集会',
imgs: ['https://facebook.github.io/react/img/logo_og.png'],
},
{
name: 'Arthur',
title: '这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章',
brief: '简介',
imgs: ['https://facebook.github.io/react/img/logo_og.png', 'https://facebook.github.io/react/img/logo_og.png'],
},
{
name: 'Arthur',
title: '这是一篇文章',
brief: '简介这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章这是一篇文章',
imgs: ['https://facebook.github.io/react/img/logo_og.png','https://facebook.github.io/react/img/logo_og.png', 'https://facebook.github.io/react/img/logo_og.png'],
},
{
name: 'Arthur',
title: '这是一篇文章',
brief: '简介',
imgs: ['https://facebook.github.io/react/img/logo_og.png','https://facebook.github.io/react/img/logo_og.png', 'https://facebook.github.io/react/img/logo_og.png'],
},
{
name: 'Arthur',
title: '这是一篇文章',
// brief: '简介',
imgs: ['https://facebook.github.io/react/img/logo_og.png','https://facebook.github.io/react/img/logo_og.png', 'https://facebook.github.io/react/img/logo_og.png'],
},
]
}
... ...
... ... @@ -5,12 +5,30 @@ import {Record, List} from 'immutable'
let InitialState = Record({
isFetching: false,
error: null,
avatar: null,
name: null,
sign: null,
post: List(), //我的帖子
praise: List(), //我赞过的
reply: List(), //我的回复
userInfo: new (Record({
avatar: null,
bgImage: null,
userName: null,
sign: null,
})),
posts: new (Record({
jsonData: List(),
pageCount:1,
currentPage: 0,
sum: 0,
})), //我的帖子
praise: new (Record({
jsonData: List(),
pageCount:1,
currentPage: 0,
sum: 0,
})) , //我赞过的
reply: new (Record({
jsonData: List(),
pageCount:1,
currentPage: 0,
sum: 0,
})), //我的回复
});
export default InitialState;
... ...
'use strict'
import InitialState from './userInitialState';
import Immutable, {List, Record} from 'immutable';
const {
USER_BACKGROUND_TAP
USER_BACKGROUND_TAP,
USER_POSTS_REQUEST,
USER_POSTS_SUCCESS,
USER_POSTS_FAILURE,
USER_LIKE_REQUEST,
USER_LIKE_SUCCESS,
USER_LIKE_FAILURE,
USER_REPLY_REQUEST,
USER_REPLY_SUCCESS,
USER_REPLY_FAILURE,
} = require('../../constants/actionTypes').default;
... ... @@ -17,13 +30,41 @@ export default function user(state = initialState, action) {
switch (action.type) {
case USER_BACKGROUND_TAP:
{
// let nextState = state.set
}
break;
{
// let nextState = state.set
}
break;
case USER_POSTS_REQUEST: {
let nextState = state.set('isFetching', true).set('error', null);
return nextState;
}
case USER_POSTS_SUCCESS:
{
// let nextState = state.set
let posts = state.posts;
let jsonData = posts.jsonData;
let origin = jsonData.toJS();
let {list} = action.payload;
let data = [...origin, ...(list || [])];
let nextState = state.set('isFetching', false)
.setIn(['posts','jsonData'], Immutable.fromJS(data));
return nextState;
}
break;
case USER_POSTS_FAILURE: {
let nextState = state.set('isFetching',false)
.set('error', action.playload);
return nextState;
}
default:
}
return state;
}
... ...
... ... @@ -21,6 +21,7 @@
"react-native-pan-controller": "0.0.1",
"react-native-router-flux": "^3.30.2",
"react-native-scrollable-tab-view": "^0.5.1",
"react-native-scrollable-mixin": "^1.0.1",
"react-native-simple-store": "^1.0.1",
"react-native-swiper": "^1.4.5",
"react-redux": "^4.4.5",
... ...