React组件不会被动地重新呈现(Redux Observable + rxjs + rx-http-requst)

时间:2017-12-03 19:33:23

标签: reactjs rxjs redux-observable

我有一个API端点,它返回'application / stream + json'类型响应中的用户列表。这些项目由换行符分隔。 可以看到示例数据here

组件

class UserList extends Component {
    componentDidMount() {
        const { fetchUsers } = this.props;
        fetchUsers();
    }

    render() {
        const { isFetching = false, users = [] } = this.props;
        if (isFetching) {
            return <Loader message="Users are loading..." />;
        }
        if (!users || users.length === 0) {
            return 'No users found.';
        }
        const children = users
            .map(user => <UserListItem key={user.id} user={user} />);
        return (
            <div className="UserList">
                <Paper>
                    <List>
                        <Subheader>Users</Subheader>
                        {children}
                    </List>
                </Paper>
            </div>
        );
    }
}

UserList.propTypes = {
    users: PropTypes.arrayOf(PropTypes.any),
    isFetching: PropTypes.bool.isRequired,
    fetchUsers: PropTypes.func.isRequired,
};

UserList.defaultProps = {
    users: [],
};

function mapStateToProps(state) {
    const { users, isFetching } = state.users;
    return {
        users,
        isFetching,
    };
}

function mapDispatchToProps(dispatch) {
    return {
        fetchUsers: bindActionCreators(actions.fetchUsers, dispatch),
    };
}

export default connect(mapStateToProps, mapDispatchToProps)(UserList);

减速

const initialState = {
    users: [],
    isFetching: false,
};

function fetchUsers(state) {
    return {
        ...state,
        isFetching: true,
    };
}

function fetchUsersItemReceived(state, action) {
    const { user } = action;
    return {
        ...state,
        users: [...state.users, user],
        isFetching: false,
    };
}

export default function (state = initialState, action) {
    switch (action.type) {
    case actionTypes.FETCH_USERS_REQUEST:
        return fetchUsers(state);
    case actionTypes.FETCH_USERS_ITEM_RECEIVED:
        return fetchUsersItemReceived(state, action);
    default:
        return state;
    }
}

操作(解析器是找到的流式JSON解析器here

export function fetchUsers() {
    return {
        type: actionTypes.FETCH_USERS_REQUEST,
    };
}

function fetchUsersItemReceived(user) {
    return {
        type: actionTypes.FETCH_USERS_ITEM_RECEIVED,
        user,
    };
}


function fetchUsersSuccess() {
    return {
        type: actionTypes.FETCH_USERS_SUCCESS,
    };
}

function fetchUsersFailure(error) {
    return {
        type: actionTypes.FETCH_USERS_FAILURE,
        error,
    };
}

function getJsonStream(url) {
    const emitter = new Subject();
    const req$ = RxHR
        .get(url)
        .flatMap(resp => resp.body)
        .subscribe(
            (data) => {
                parser.write(data);
                parser.onValue = (value) => {
                    if (!parser.key) {
                        emitter.next(value);
                    }
                };
            },
            err => emitter.error(err),
            () => emitter.complete(),
        );
    return emitter;
}

export const fetchUsersEpic = action$ =>
    action$.ofType(actionTypes.FETCH_USERS_REQUEST)
        .concatMap(() => getJsonStream(`${api.API_BASE_URL}/user`))
        .map(user => fetchUsersItemReceived(user));

configureStore.js

const logger = createLogger();

const epicMiddleware = createEpicMiddleware(rootEpic);
const createStoreWithMiddleware = applyMiddleware(epicMiddleware, logger)(createStore);

export default function configureStore(initialState) {
    return createStoreWithMiddleware(rootReducer, initialState);
}

虽然在收到EACH项目后应刷新列表组件,但在收到整个列表后会刷新列表组件。有人能指出代码中的阻塞点吗?

2 个答案:

答案 0 :(得分:0)

这不是解决您的特定问题的解决方案(除非偶然lol)但我认为自定义Observable更适合这种情况而不是主题。您也可以加入Parser的错误回调。

想到以后用rxjs搜索流式JSON的其他人可能会发现这个方便(未经测试)

django-taggit

如果你有机会把jsbin放在一起让我知道!

答案 1 :(得分:0)

原来问题在于jsonParse lib。切换到oboe.js 固定它。使用 ”!”节点选择器,用于选择多个根JSON元素,我能够将字符流转换为用户对象流。

<强>动作

function getJsonStream(url) {
    const emitter = new Subject();
    const emitter = new Subject();
    oboe(url)
        .node('!', (item) => {
            emitter.next(item);
        })
        .fail((error) => {
            emitter.error(error);
        });
    return emitter;
}

export const fetchUsersEpic = action$ =>
    action$.ofType(actionTypes.FETCH_USERS_REQUEST)
        .switchMap(() => getJsonStream(`${api.API_BASE_URL}/user`))
        .map(user => fetchUsersItemReceived(user));