美文网首页
redux 使用

redux 使用

作者: 日不落000 | 来源:发表于2017-12-05 18:49 被阅读17次

    package.json

    "dependencies": {
        "react-redux": "^5.0.6",
        "redux": "^3.7.2",
        "redux-thunk": "^2.2.0",
    }
    
    "devDependencies": {
        "remote-redux-devtools": "^0.5.12",
        "remote-redux-devtools-on-debugger": "^0.8.3",
      },
    
    import { Provider } from "react-redux";
    import store from "./store/store.js";
    
    <Provider store={store}>
        <MyRootComponent />
      </Provider>
    

    ./store/store.js

    /**
     * Created by nick on 2017/12/4.
     */
    import allReducers from "../reducers/index.js";
    
    import { applyMiddleware, createStore } from "redux";
    /**
     * Logs all actions and states after they are dispatched.
     */
    const logger = store => next => action => {
        console.group(action.type);
        console.info('dispatching', action);
        let result = next(action);
        console.log('next state', store.getState());
        console.groupEnd(action.type);
        return result;
    };
    
    /**
     * Sends crash reports as state is updated and listeners are notified.
     */
    // const crashReporter = store => next => action => {
    //     try {
    //         return next(action)
    //     } catch (err) {
    //         console.error('Caught an exception!', err)
    //         Raven.captureException(err, {
    //             extra: {
    //                 action,
    //                 state: store.getState()
    //             }
    //         })
    //         throw err
    //     }
    // }
    
    /**
     * Schedules actions with { meta: { delay: N } } to be delayed by N milliseconds.
     * Makes `dispatch` return a function to cancel the timeout in this case.
     */
    const timeoutScheduler = store => next => action => {
        if (!action.meta || !action.meta.delay) {
            return next(action);
        }
    
        let timeoutId = setTimeout(
            () => next(action),
            action.meta.delay
        );
    
        return function cancel() {
            clearTimeout(timeoutId);
        };
    };
    
    /**
     * Schedules actions with { meta: { raf: true } } to be dispatched inside a rAF loop
     * frame.  Makes `dispatch` return a function to remove the action from the queue in
     * this case.
     */
    const rafScheduler = store => next => {
        let queuedActions = [];
        let frame = null;
    
        function loop() {
            frame = null;
            try {
                if (queuedActions.length) {
                    next(queuedActions.shift());
                }
            } finally {
                maybeRaf();
            }
        }
    
        function maybeRaf() {
            if (queuedActions.length && !frame) {
                frame = requestAnimationFrame(loop);
            }
        }
    
        return action => {
            if (!action.meta || !action.meta.raf) {
                return next(action);
            }
    
            queuedActions.push(action);
            maybeRaf();
    
            return function cancel() {
                queuedActions = queuedActions.filter(a => a !== action);
            };
        };
    };
    
    /**
     * Lets you dispatch promises in addition to actions.
     * If the promise is resolved, its result will be dispatched as an action.
     * The promise is returned from `dispatch` so the caller may handle rejection.
     */
    const vanillaPromise = store => next => action => {
        if (typeof action.then !== 'function') {
            return next(action);
        }
    
        return Promise.resolve(action).then(store.dispatch);
    };
    
    /**
     * Lets you dispatch special actions with a { promise } field.
     *
     * This middleware will turn them into a single action at the beginning,
     * and a single success (or failure) action when the `promise` resolves.
     *
     * For convenience, `dispatch` will return the promise so the caller can wait.
     */
    const readyStatePromise = store => next => action => {
        if (!action.promise) {
            return next(action);
        }
    
        function makeAction(ready, data) {
            let newAction = Object.assign({}, action, { ready }, data);
            delete newAction.promise;
            return newAction;
        }
    
        next(makeAction(false));
        return action.promise.then(
            result => next(makeAction(true, { result })),
            error => next(makeAction(true, { error }))
        );
    };
    
    /**
     * Lets you dispatch a function instead of an action.
     * This function will receive `dispatch` and `getState` as arguments.
     *
     * Useful for early exits (conditions over `getState()`), as well
     * as for async control flow (it can `dispatch()` something else).
     *
     * `dispatch` will return the return value of the dispatched function.
     */
    const thunk = store => next => action =>
        typeof action === 'function'
            ? action(store.dispatch, store.getState)
            : next(action);
    
    // You can use all of them! (It doesn't mean you should.)
    
    let store = createStore(
        allReducers,
        applyMiddleware(
            rafScheduler,
            timeoutScheduler,
            thunk,
            vanillaPromise,
            readyStatePromise,
            logger
        )
    );
    
    module.exports = store;
    
    

    todoActionCreators.js

    /**
     * Created by nick on 2017/12/4.
     */
    export const ADD_TODO = 'ADD_TODO';
    export const SET_INPUT_TEXT = 'SET_INPUT_TEXT';
    
    /*
     * action creators
     */
    
    export function addTodo(text) {
        return { type : ADD_TODO, text };
    }
    
    export function setInputText(text) {
        return { type : SET_INPUT_TEXT, text };
    }
    
    //todo async
    
    export const REQUEST_POSTS = 'REQUEST_POSTS';
    function requestPosts(subreddit) {
        return {
            type : REQUEST_POSTS,
            subreddit
        };
    }
    
    export const RECEIVE_POSTS = 'RECEIVE_POSTS';
    function receivePosts(subreddit, json) {
        return {
            type : RECEIVE_POSTS,
            subreddit,
            posts : json.data.children.map(child => child.data),
            receivedAt : Date.now()
        };
    }
    
    // 来看一下我们写的第一个 thunk action creator!
    // 虽然内部操作不同,你可以像其它 action creator 一样使用它:
    // store.dispatch(fetchPosts('reactjs'))
    
    export function fetchPostsOld(subreddit) {
    
        // Thunk middleware 知道如何处理函数。
        // 这里把 dispatch 方法通过参数的形式传给函数,
        // 以此来让它自己也能 dispatch action。
    
        return function (dispatch) {
    
            // 首次 dispatch:更新应用的 state 来通知
            // API 请求发起了。
    
            dispatch(requestPosts(subreddit))
    
            // thunk middleware 调用的函数可以有返回值,
            // 它会被当作 dispatch 方法的返回值传递。
    
            // 这个案例中,我们返回一个等待处理的 promise。
            // 这并不是 redux middleware 所必须的,但这对于我们而言很方便。
    
            return fetch(`http://www.subreddit.com/r/${subreddit}.json`)
                .then(response => response.json())
                .then(json =>
    
                    // 可以多次 dispatch!
                    // 这里,使用 API 请求结果来更新应用的 state。
    
                    dispatch(receivePosts(subreddit, json))
                )
    
            // 在实际应用中,还需要
            // 捕获网络请求的异常。
        }
    }
    
    export function fetchPosts(subreddit) {
    
        // Thunk middleware 知道如何处理函数。
        // 这里把 dispatch 方法通过参数的形式传给函数,
        // 以此来让它自己也能 dispatch action。
    
        // OtherApi.postInfoNormalNoAccessTokenTestRedux(`http://www.subreddit.com/r/${subreddit}.json`,{},(jsonObj)=>{
        //     console.log(jsonObj);
        // })
        //
        // return;
    
        return async function (dispatch) {
    
            // 首次 dispatch:更新应用的 state 来通知
            // API 请求发起了。
    
            dispatch(requestPosts(subreddit));
    
            // thunk middleware 调用的函数可以有返回值,
            // 它会被当作 dispatch 方法的返回值传递。
    
            // 这个案例中,我们返回一个等待处理的 promise。
            // 这并不是 redux middleware 所必须的,但这对于我们而言很方便。
    
            // return fetch(`http://www.subreddit.com/r/${subreddit}.json`)
            //     .then(response => response.json())
            //     .then(json =>
            //
            //         // 可以多次 dispatch!
            //         // 这里,使用 API 请求结果来更新应用的 state。
            //
            //         dispatch(receivePosts(subreddit, json))
            //     );
            //
    
            let responseJson = await postAsync(`http://www.subreddit.com/r/${subreddit}.json`, {}, subreddit, dispatch)
    
            dispatch(receivePosts(subreddit, responseJson))
    
            return;
    
            // 在实际应用中,还需要
            // 捕获网络请求的异常。
        };
    }
    
    async function postAsync(url, bodyObject, subreddit, dispatch) {
        let headers = {
            'Accept' : 'application/json',
            'Content-Type' : 'application/json',
        };
    
        let response
            = await
            fetch(url, {
                method : 'POST',
                headers : headers,
                body : JSON.stringify(bodyObject),
            });
        console.log(response);
    
        let responseJson
            = await
            response.json();
        console.log(responseJson);
        // console.log(StringUtil.object2Json(responseJson));
    
        return responseJson;
    
    };
    
    
    

    ./reducers/todoReducer.js

    /**
     * Created by nick on 2017/12/5.
     */
    import { combineReducers } from "redux";
    import { ADD_TODO, RECEIVE_POSTS, SET_INPUT_TEXT, } from "../actions/todoActionCreators";
    
    function header_input_value(state = 'header_input_value', action) {
        switch (action.type) {
            case SET_INPUT_TEXT:
                return action.text;
            default:
                return state;
        }
    }
    
    function receivePost(state = {}, action) {
        switch (action.type) {
            case RECEIVE_POSTS:
                return action;
            default:
                return state;
        }
    }
    
    function todos(state = [ { text : "Use Redux11", completed : false } ], action) {
        switch (action.type) {
            case ADD_TODO:
                return [
                    ...state,
                    {
                        text : action.text,
                        completed : false
                    }
                ];
            case TOGGLE_TODO:
                return state.map((todo, index) => {
                    if (index === action.index) {
                        return Object.assign({}, todo, {
                            completed : !todo.completed
                        });
                    }
                    return todo;
                });
            default:
                return state;
        }
    }
    
    const todoApp = combineReducers({
        header_input_value,
        receivePost,
        todos
    });
    
    export default todoApp;
    

    ./reducers/index.js

    import { combineReducers } from "redux";
    import todoReducer from "./todoReducer.js";
    
    const allReducers = combineReducers({
        todoReducer,
    });
    
    export default allReducers;
    

    ZZTestReduxTodoListScreen.js

    /**
     * Created by nick on 2017/4/20.
     * https://redux.js.org/docs/basics/ExampleTodoList.html
     */
    import React, { Component } from "react";
    import { Container, Content } from "native-base";
    import ConstantUtil from "../utils/ConstantUtil";
    import { InteractionManager, Text, View } from "react-native";
    import BaseCommon from "../common/BaseCommon";
    import HeaderNormalWithRightButtonAndSearch from "../components/HeaderNormalWithRightButtonAndSearch";
    import { connect } from "react-redux";
    import { bindActionCreators } from "redux";
    import * as todoActionCreators from "../actions/todoActionCreators";
    import MyButton from "../components/MyButton";
    import * as StyleUtil from "../utils/StyleUtil";
    
    class TodoList extends Component {
        render() {
            let { todos } = this.props;
            let _view = null;
    
            _view = (
                <View>
                    {todos && todos.length > 0 ? todos.map(
                        (item, i) => {
                            return (
                                <Text key={`key_${i}`}>{item.text}</Text>
                            );
                        }
                    )
                        : null
                    }
                </View>
            );
            return _view;
    
        }
    }
    
    class ZZTestReduxTodoListScreen extends Component {
    
        static propTypes = {
            header_title : React.PropTypes.string,       //
    
        };
    
        static defaultProps = {
            header_title : '',
        };
    
    
        constructor(props) {
            super(props);
            const { dispatch } = props;
    
            // Here's a good use case for bindActionCreators:
            // You want a child component to be completely unaware of Redux.
            // We create bound versions of these functions now so we can
            // pass them down to our child later.
    
            this.boundActionCreators = bindActionCreators(todoActionCreators, dispatch)
            console.log(this.boundActionCreators)
            // {
            //   addTodo: Function,
            //   removeTodo: Function
            // }
    
    
            this.state = {
            };
        }
    
        componentDidMount() {
            console.log(this);
            let { actions } = this.props
    
            // Note: this won't work:
            // TodoActionCreators.addTodo('Use Redux')
    
            // You're just calling a function that creates an action.
            // You must dispatch the action, too!
    
            // This will work:
            actions.addTodo('Use Redux')
    
        }
    
        componentWillMount() {
        }
    
        componentWillUnmount() {
        }
    
        componentWillReceiveProps(nextProps) {
        }
    
        render() {
    
            let { header_input_value, receivePost } = this.props;
            let { setInputText, fetchPosts } = this.props.actions;
    
            let _viewHeader = null;
            _viewHeader = (
                <HeaderNormalWithRightButtonAndSearch
                    _rightBtnShouldShow={true}
                    _textBtn={'添 加'}
                    _onPressBtn={() => {
                        let { actions } = this.props
    
                        // Note: this won't work:
                        // TodoActionCreators.addTodo('Use Redux')
    
                        // You're just calling a function that creates an action.
                        // You must dispatch the action, too!
    
                        // This will work:
                        actions.addTodo(header_input_value)
                    }}
    
                    _inputPlaceHolder={this.props.header_input_place_holder}
                    _inputDefaultValue={header_input_value}
                    _inputValue={header_input_value}
                    _onChange={(value) => {
    
                        setInputText(value);
    
                    }}
                />
            );
            let { todos } = this.props
    
            return (
                <Container style={{ backgroundColor : ConstantUtil.colors.bgGray }}>
    
                    {_viewHeader}
    
                    <Content
                        keyboardShouldPersistTaps='always'
                        // keyboardDismissMode={'on-drag'}
                        showsVerticalScrollIndicator={false}
    
                        contentContainerStyle={{
                            justifyContent : 'center',
                            alignItems : 'stretch',
                            flex : 1,
                        }}>
    
                        <MyButton
                            textStyle={[ StyleUtil.gStyles.gButtonTextWhiteDefault, ]}
                            buttonStyle={[ StyleUtil.gStyles.gButtonBlueDefault, {}, ]}
                            onClick={() => {
    
                                fetchPosts(header_input_value);
    
                            }}
                        >
                            <Text> 网络请求 </Text>
                        </MyButton>
    
                        <Text>{receivePost.receivedAt}</Text>
                        <Text style={{ width : StyleUtil.size.width, height : 100, }}>{JSON.stringify(receivePost)}</Text>
    
                        <TodoList todos={todos} {...this.boundActionCreators} />
    
                    </Content>
    
                </Container>
            );
        }
    
    }
    function mapStateToProps(state) {
        return {
            todos : state.todoReducer.todos,
            header_input_value : state.todoReducer.header_input_value,
            receivePost : state.todoReducer.receivePost,
        };
    }
    
    function mapDispatchToProps(dispatch) {
        return { actions : bindActionCreators(todoActionCreators, dispatch) };
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(ZZTestReduxTodoListScreen);
    
    
    

    re.
    http://www.redux.org.cn/docs/advanced/AsyncActions.html

    相关文章

      网友评论

          本文标题:redux 使用

          本文链接:https://www.haomeiwen.com/subject/hgncixtx.html