react-redux 初始化 获取 数据,并生成元素加入到页面上 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
eromoe
V2EX    React

react-redux 初始化 获取 数据,并生成元素加入到页面上

  •  
  •   eromoe 2016-06-20 12:32:02 +08:00 13822 次点击
    这是一个创建于 3451 天前的主题,其中的信息可能已经有所发展或是发生改变。

    先吐槽一下 V2EX 没有保存草稿的功能,因为挂代理上的,发布的时候代理抽风了,结果写了半天全没了。。。。

    言归正传,我这 2,3 周零零碎碎的在看 react,redux,route 想从大项目里一下子把这一揽子全部搞懂(周边还有什么 webpack es6 只弄懂基本, js 的很多原生方法都没搞清楚,比如在 ajax 后面加 bind 之类的的) 看了很多例子,官方教程也看了,发现好多例子写法都不同,在 ajax 上就更不同了。。。虽然有些都是用什么 thunk 但是写的东西感觉不一样。。。小项目初始化都是直接 给 state/props 一个值,然后在 render 里直接传进去,大项目写的我根本看不懂在哪里拿的数据。。。。

    现在想自己个项目来弄懂这些问题,准备弄个 bypy 的 file manager webui , 结合了 2 个我觉得比较能看懂的项目(一个 redux demo 一个 react route 的 demo )

    搞了半天,route怎么都显示不出来。。。所以先去掉了。。。先搞初始化 因为 file manager 所有点击的节点都是一样的,我想做一个自包含的 componnent ,但是由于初始化传参的问题,感觉怎么写都不对。。。所以想先把这个搞懂,就做了个最简单: App 显示根目录下的所有节点(TreeNode)

    但是碰到了个错误 Uncaught TypeError: Cannot read property 'nodes' of null 在 App.render 的地方报错的

    主要代码如下

    containers/App.js:

    import React, { Component, PropTypes } from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import {getFileList} from '../actions/NodeActions' import Footer from '../components/Footer'; import TreeNode from '../containers/TreeNode'; import Home from '../containers/Home'; export default class App extends Component { componentDidMount() { let nodes = getFileList(); this.setState({ nodes: nodes }); } render() { const { actions } = this.props; const { nodes } = this.state; return ( <div className="main-app-container"> <Home /> <div className="main-app-nav">Simple Redux Boilerplate</div> {nodes.map(node => <TreeNode key={node.name} node={node} {...actions} /> )} <Footer /> </div> ); } } function mapStateToProps(state) { return { test: state.test }; } function mapDispatchToProps(dispatch) { return { actions: bindActionCreators(getFileList, dispatch) }; } export default connect( mapStateToProps, mapDispatchToProps )(App); 

    actions/NodeActions.js:

    import { OPEN_NODE, CLOSE_NODE } from '../constants/ActionTypes'; export function openNode() { return { type: OPEN_NODE }; } export function closeNode() { return { type: CLOSE_NODE }; } class NodeModel { constructor(name, path, type, right) { this.name = name; this.path = path; this.type = type; this.right = right; } } const testNodes = [ new NodeModel('t1','t1', 'd', '777'), new NodeModel('t2','t2', 'd', '447'), new NodeModel('t3','t3', 'd', '667'), ] export function getFileList() { return { nodes: testNodes } } export function ansyncGetFileList() { return dispatch => { setTimeout(() => { dispatch(getFileList()); }, 1000); }; } 

    1.我觉得可能是 testNodes 不能那么初始化,就直接改成了

    const testNodes = [ {name:'t1',type:'t1'}, {name:'t2',type:'t2'}, {name:'t3',type:'t3'}, ] 

    没效果

    2.可能是 scope 的原因,就把 testNodes 移到 getFileList 里,还是同样的错。

    真的 have no idea.

    13 条回复    2016-06-20 20:26:42 +08:00
    spritevan
        1
    spritevan  
       2016-06-20 13:11:16 +08:00
    let nodes = getFileList();
    // getFileList = () => { nodes: [...] }
    // this.state.nodes = { nodes: [] }

    App.render() 里面应该要用 `nodes.nodes.map()` 吧?
    yesmeck
        2
    yesmeck  
       2016-06-20 13:19:07 +08:00
    ```Javascript
    // state 一个初始值
    // 因为 componentDidMount 在 render 后执行,所以第一次 rander 的时候, state 还没 nodes
    constructor(props) {
    super(props)

    this.state = {
    nodes: []
    }
    }
    ```

    ```Javascript
    function mapDispatchToProps(dispatch) {
    return {
    actions: bindActionCreators(getFileList, dispatch) // getFileList 并不是个 action creator ,不需要 bind
    };
    }
    ```
    eromoe
        3
    eromoe  
    OP
       2016-06-20 14:00:54 +08:00
    @spritevan 噢!谢谢指出, 这里是不是用 var { xx } = xxx; 或者 {...nodes} 更好?

    @yesmeck
    加了 constructor ,我在想是不是能在 constructor 里直接赋初始值,但是好像又在哪里看到 react 不建议这么做,又好像没有。。。
    代码改成下面这样
    1.
    ```
    render() {
    const {actions } = this.props
    const { nodes } = this.state
    console.log(nodes)
    return (
    <div className="main-app-container">
    <Home />
    <div className="main-app-nav">Simple Redux Boilerplate</div>
    {nodes.nodes.map(node =>
    <TreeNode key={node.name} node={node} {...actions} />
    )}
    <Footer />
    </div>
    );
    }
    ```
    log 出来如下,而且页面不显示

    []

    错误:App.js?4495:35 Uncaught TypeError: Cannot read property 'map' of undefined

    2.

    ```
    render() {
    const { actions } = this.props
    const { nodes } = this.state
    console.log(nodes)
    return (
    <div className="main-app-container">
    <Home />
    <div className="main-app-nav">Simple Redux Boilerplate</div>
    {nodes.map(node =>
    <TreeNode key={node.name} node={node} {...actions} />
    )}
    <Footer />
    </div>
    );
    }
    ```
    不用 nodes.nodes.map ,会 log 2 遍,然后显示出页面 ,并报错

    []
    Object {nodes: Array[3]}

    错误 : App.js?4495:35 Uncaught TypeError: nodes.map is not a function

    3. 修改赋值部分
    ```
    componentDidMount() {
    let {nodes} = getFileList()
    this.setState({
    nodes: nodes
    })
    }
    ```
    使用 2. 原始的 render 就不会出错,按理来说
    var { nodes} = getFileList();
    nodes.map

    应该等于
    var nodes = getFileList();
    nodes.nodes.map

    好奇怪。。。
    yesmeck
        4
    yesmeck  
       2016-06-20 14:07:06 +08:00   1
    评论代码不能高亮太难看了,可以的话你把代码放 github 上我可以帮你看看。
    eromoe
        5
    eromoe  
    OP
       2016-06-20 14:23:18 +08:00
    eromoe
        6
    eromoe  
    OP
       2016-06-20 14:36:01 +08:00
    一开始没想到,只要下面这么简单就行了,因为总是觉得 reducer 只是用来更新的,不能初始化,又戳破了一个盲点~

    componentWillMount() {
    // this will update the nodes on state
    this.props.getFileList();
    }

    render() {
    // will be re-rendered once store updated
    const {nodes} = this.props;
    // use nodes
    }

    function mapStateToProps(state) {
    return {
    nodes: state.nodes
    };
    }

    export default connect(
    mapStateToProps,
    { getFileList: ansyncGetFileList }
    )(App);
    yesmeck
        7
    yesmeck  
       2016-06-20 14:54:55 +08:00   1
    @eromoe github 上回复你了
    eromoe
        8
    eromoe  
    OP
       2016-06-20 15:11:55 +08:00
    @yesmeck 非常感谢! 我刚刚也是发现能直接用这个 this.props.getFileList(); 然后豁然开朗, 现在感觉都串起来了~谢谢~
    eromoe
        9
    eromoe  
    OP
       2016-06-20 17:24:16 +08:00
    @yesmeck
    又发现个问题。。。 我想把 node 的信息显示出来
    App.render:
    ```
    {nodes.map(node =>
    <TreeNode key={node.name} info={node} />
    )}
    ```

    在 TreeNode.render:
    ```
    const { actions, nodes, info } = this.props
    return (
    <a>{info.name}</a>
    );
    ```

    貌似 info 没有传进去。。。 log 显示是 undefined


    warning.js?8a56:45 Warning: Failed propType: Required prop `info` was not specified in `TreeNode`. Check the render method of `Connect(TreeNode)`.

    TreeNode.js?10ab:57 Uncaught TypeError: Cannot read property 'name' of undefined


    google 了一圈 没看到问类似问题的,都是什么 parent 传数据到 child 的问题,他们的 child 都是已经存在的。。。
    如果这些信息没办法判断问题的话, 我也更新了 gitbub
    yesmeck
        10
    yesmeck  
       2016-06-20 17:29:18 +08:00
    没看到 github 有更新
    eromoe
        11
    eromoe  
    OP
       2016-06-20 17:33:38 +08:00
    @yesmeck Oh! 不好意思。。。换了台机子, ssh 有 passphrase , git push 之后就没注意。。。
    eromoe
        12
    eromoe  
    OP
       2016-06-20 20:25:15 +08:00
    @yesmeck 找到问题了~ 我在 TreeNode 下面也写了 connect , 原来所有子元素都是需要继承父元素的啊,除非是不同的根元素,否组不能加 connect 。
    ericls
        13
    ericls  
       2016-06-20 20:26:42 +08:00 via iPhone
    建议用 thunk
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     969 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 22:39 PVG 06:39 LAX 14:39 JFK 17:39
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86