美文网首页JavaScript学习笔记
当下对React.js的再思考

当下对React.js的再思考

作者: 钢笔先生 | 来源:发表于2019-11-27 23:25 被阅读0次

    Time: 2019-11-27

    之前在比赛中写前端工程时,使用了如下几个关键的技术点:

    • redux,负责应用状态管理
    • reux-thunk,负责中间件管理
    • 容器组件
    • 展示组件
    • reducer
    • action

    首先从redux讲起。

    redux的设计原则是用单个字典来存储应用的状态树store,通过action来传递修改状态的信息包,具体的修改是通过定义的reducers函数来执行。

    也即我们需要将actions --> reducers --> store三者串联起来。

    这三者是为了搭建起来一个自动响应的框架,搭建完是不动的,需要外界dispatch某个action来触发,相当于现在定义了一个状态机,外界的输入进来才会触发响应。

    store会在应用的index.js中绑定到全局。

    import { store } from './_store'
    
    const rootElement = document.getElementById("root")
    
    console.log("store状态:", store.getState()) // 可以拿到状态
    
    // store已经绑定到了整个App
    ReactDOM.render(
        <Provider store={store}>
            <App />
        </Provider>, rootElement
    )
    

    一般我们会定义一个store.js用于表示状态,我们会

    关于组件,我们抽象为两层组件:

    • 容器组件
    • 展示组件

    容器组件负责将状态和要触发的动作绑定到展示组件,展示组件只需要关注自己如何通过HTML + CSS元素表达想要展示的内容,容器组件会把要用到的数据和要dispatch的动作注入到展示组件的props

    举个例子:

    import { Blacklist } from '../../_pages/company'
    import { connect } from 'react-redux'
    import { listBlacklistAsync } from '../../_actions/company.actions'
    
    // 容器负责注入状态显示和行为定义,作为显示组件的props
    
    // store状态映射到组件
    // store已经在index.js中绑定到应用,这里直接取用即可
    // blacklist是用于props的键
    const mapStateToProps = state => ({
        blacklist: state.company.blacklist,
        fetchStatus: state.company.fetchStatus,
    })
    
    // 注入到展示组件的props中的回调方法
    const mapDispatchToProps = dispatch => ({
        listBlacklistAsync: () => dispatch(listBlacklistAsync())
    })
    
    // 连接到展示组件
    export default connect(
        mapStateToProps,
        mapDispatchToProps
    )(Blacklist)
    
    

    容器组件和展示组件通过connect方法绑定到一起。背后store状态机已经搭建好了。

    展示组件调用容器组件准备好的属性和方法:

    componentDidMount() {
            this.props.listBlacklistAsync() // 先分发查询修改状态树
        }
    
    
    render() {
            // this.createData(`0xc83b2cf766d3165acc2fc9164641380088defd1b`, "xx于xx年xx月xx日未还款金额xx元"),
            let rows = []
            // 需要根据状态判定是否已经结束获取
            console.log("组件内显示黑名单:", this.props.blacklist)
    
            if (this.props.blacklist !== undefined) {
                // this.props.blacklist.map((item, i) => {
                //     rows.push(this.createData(item.weid, item.record))
                // })
                rows = this.props.blacklist
            }
    
            const { classes } = this.props
    
            if (this.props.fetchStatus === FETCH_STATUS.FETCH_BEGIN) {
                return (
                    <div align="center">
                        <br />
                        <CircularProgress />
                    </div>
                )
            }
    ....
    

    关于action的定义:

    程序需要调用的外部数据,我们用fetch获取,获取到的数据可以用到action定义中,外部数据的获取是为了修改组件的状态,而组件的状态现在是由store接管。

    看一个action定义的例子:

    
    // dispatch action
    const listLoanRequestRecords = (json) => {
        return {
            type: types.LOAN_REQUEST_RECORDS,
            payload: json.data
        }
    }
    
    
    // 定义行为,行为会在容器组件中设定给props,具体显示组件中择时触发
    const listLoanRequestRecordsAsync = () => {
        return dispatch => {
            dispatch(fetchBegin())
            // 通过服务拿到数据,最后作为action的payload,action的payload用于修改store,修改行为由reducer执行
            companyServices.listLoanRequestRecords("WeBank").then(
                json => {
                    if (json.status === 200) {
                        dispatch(fetchSuccess())
                    }
                    dispatch(listLoanRequestRecords(json))
                }
            )
        }
    }
    

    action是在reducers中使用。所以我们看下reducers的定义:

    // 获取用户请求列表
    export function loanRequestRecordsReducer(state = [], action) {
        switch (action.type) {
            case types.LOAN_REQUEST_RECORDS:
                return [
                    ...state,
                    ...action.payload
                ]
            default:
                return state
        }
    }
    

    reducer是纯函数,接收当前状态的值然后根据action带来的动作类型和数据包修改store。

    不要看参数state=[]就认为store是空,这是默认参数,拿到的是当前的数据。

    另外,reducer指定的键名就是store字典树的键名。

    比如在store中:

    // 会根据定义的键值生成对应的以第一层键指定的store
    const rootReducer = combineReducers({
        company: companyReducer,
        government: governmentReducer,
        user: userReducer,
        common: commonReducer
    })
    
    

    一级键就是这四个值:company, government, user, common

    这个之前写过一个笔记:
    在combineReducers用的是对象,按照key来标记对应的是哪个reducer,键是state的属性名!

    这太重要了,我太喜欢这个了,解决了我的困惑。

    下一个困惑是,state给空,每次调用都是在干嘛?

    是根据分离的reducer对应的属性直接抽出来一段数据过来当参数吗?

    如果修改的话就在容器组件中dispatch修改方法

    如果只是读取,就在容器组件中getState传到值属性里。

    Q: fetch返回的Promise如何触发状态更新?

    A: fetch(url).then(response => response.json()).then(json => console.log(json))

    这样就串起来应用状态和数据读取的全貌了。

    有点乱,后续有时间再梳理。

    相关文章

      网友评论

        本文标题:当下对React.js的再思考

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