Skip to content

Instantly share code, notes, and snippets.

@xyzdata
Created July 12, 2017 01:21
Show Gist options
  • Save xyzdata/a2a2943e8338452a8c6c8b7c254a4d79 to your computer and use it in GitHub Desktop.
Save xyzdata/a2a2943e8338452a8c6c8b7c254a4d79 to your computer and use it in GitHub Desktop.
dva-router

dva-router

https://github.com/pmg1989/dva-admin/blob/master/src/index.js

    
import dva from 'dva';
import { browserHistory } from 'dva/router';
import createLoading from 'dva-loading';
import { message } from 'antd';

import './index.html';
import './index.css';

// 3 秒
const ERROR_MSG_DURATION = 3; 

// 1. Initialize
const app = dva({
    history: browserHistory,
    onError(e) {
        message.error(e.message, ERROR_MSG_DURATION);
        console.error("app onError -- ", error);
    }
});

// 2. Plugins
app.use(createLoading());

// 3. Model
// Moved to router.js
// app.model(require('./models/users'))

// 4. Router for browserHistory
app.router(require('./router'));

// 5. Start
app.start('#root');

dva knowledge map

https://github.com/dvajs/dva-knowledgemap#通过-connect-绑定数据

https://github.com/dvajs/dva-knowledgemap#增删改

@xyzdata
Copy link
Author

xyzdata commented Jul 12, 2017

Warning: getFieldDecorator will override value, so please don't set value directly and use setFieldsValue to set it.

@xyzdata
Copy link
Author

xyzdata commented Jul 12, 2017

must keep input type same

The specified value "new pid" is not a valid number.
The value must match to the following regular expression: -?(\d+|\d+.\d+|.\d+)([eE][-+]?\d+)?


initialValue: item ? item.picurls : [],

异常处理

initialValue: record.pname ? record.pname : null_pname,

too much bugs!

type="number" === initialValue: record.pname,

must keep input type same

    <FormItem
        label={<span className="left-spaces">角色编码:</span>}
        style={{}}
        >
        {
            getFieldDecorator('roleCode', {
                initialValue: record.pname,
                rules: [{ required: false, message: '角色编码' }],
            })
            (
                <Input 
                    prefix={<Icon type="user" style={{ fontSize: 13 }} />} 
                    type="number" 
                    placeholder="角色编码" 
                    />
            )
        }
    </FormItem>

ant-design/ant-design#3976

@xyzdata
Copy link
Author

xyzdata commented Jul 12, 2017

E:\xgqfrms\src-2017-6-22\src\Ant_Components\Form.jsx

import React, {Component} from 'react';

import {Form, Icon, Input, Button} from 'antd';

const FormItem = Form.Item;

const hasErrors = (fieldsError) => {
    // 测试数组中的某些元素是否通过由提供的函数实现的测试。
    return Object.keys(fieldsError).some(field => fieldsError[field]);
};

class HorizontalLoginForm extends React.Component {
    componentDidMount() {
        // To disabled submit button at the beginning.
        this.props.form.validateFields();
    }
    handleSubmit = (e) => {
        e.preventDefault();
        this.props.form.validateFields((err, values) => {
            if (!err) {
                console.log('Received values of form: ', values);
            }
        });
    }
    render() {
        // 解构赋值
        const {getFieldDecorator, getFieldsError, getFieldError, isFieldTouched} = this.props.form;
        // Only show error after a field is touched.
        const userNameError = isFieldTouched('userName') && getFieldError('userName');
        const passwordError = isFieldTouched('password') && getFieldError('password');
        return (
            <Form layout="inline" onSubmit={this.handleSubmit}>
                <FormItem
                    validateStatus={userNameError ? 'error' : ''}
                    help={userNameError || ''}
                    >
                    {
                        getFieldDecorator('userName', {
                            rules: [{ required: true, message: 'Please input your username!' }],
                        }
                        )
                        (
                        <Input prefix={<Icon type="user" style={{ fontSize: 13 }} />} placeholder="Username" />
                        )
                    }
                </FormItem>
                <FormItem
                    validateStatus={passwordError ? 'error' : ''}
                    help={passwordError || ''}
                    >
                    {
                        getFieldDecorator('password', {
                            rules: [{ required: true, message: 'Please input your Password!' }],
                        })
                        (
                            <Input prefix={<Icon type="lock" style={{ fontSize: 13 }} />} type="password" placeholder="Password" />
                        )
                    }
                </FormItem>
                <FormItem>
                    <Button
                        type="primary"
                        htmlType="submit"
                        disabled={hasErrors(getFieldsError())}
                        >
                        Log in
                    </Button>
                </FormItem>
            </Form>
        );
    }
}

const WHLF = Form.create({})(HorizontalLoginForm);

export {WHLF};

export default WHLF;

/*
ReactDOM.render(<WrappedHorizontalLoginForm />, mountNode);


经 Form.create() 包装过的组件会自带 this.props.form 属性,直接传给 Form 即可。
1.7.0 之后无需设置

object	无


this.props.form



https://react-component.github.io/form/

React High Order Form Component


*/











/*



https://ant.design/components/form-cn/#API


layout	表单布局(2.8 之后支持)	'horizontal'|'vertical'|'inline'

onSubmit	数据验证成功后回调事件	Function(e:Event)	

hideRequiredMark	隐藏所有表单项的必选标记	Boolean	false


form 经 Form.create() 包装过的组件会自带 this.props.form 属性,直接传给 Form 即可。

https://react-component.github.io/form/


https://github.com/react-component

https://facebook.github.io/react/docs/handling-events.html


*/

@xyzdata
Copy link
Author

xyzdata commented Jul 12, 2017

ProductManagement

just for testing!

import React, {Component} from 'react';

import {Table, Form, Icon, Input, Button, Modal} from 'antd';

import {SignUpDialog} from './utils/FancyBox';

import {EM} from './Modals/EditModal';




// import {ET} from './utils/EditTable';


// key	React 需要的 key,如果已经设置了唯一的 dataIndex,可以忽略这个属性

// dataIndex	列数据在数据项中对应的 key,支持 a.b.c 的嵌套写法
const columns = [
    {
        title: '产品名称 ',
        dataIndex: 'pname',
        key: 'productName'
    }, 
    {
        title: '产品ID',
        dataIndex: 'pid',
        key: 'productId',
        render: ((text) => (<a href="#">{text}</a>))
    }, 
    {
        title: '最新版本',
        dataIndex: 'lversion',
        key: 'latestVersion'
    },
    {
        title: '关联菜单',
        dataIndex: 'rmenu',
        key: 'relationMenu',
        render: (
            (text, record, index) => {
                console.log(`record`, record);
                const style1= `
                    color: red;
                    font-size: 16px;
                `;
                const style2= `
                    color: #f0f;
                    font-size: 16px;
                `;
                return(
                    <a href="#" onClick={
                        () => {
                             {/*alert(record.pid);*/}
                             console.log(`%c record.pid`, `${style1}`, record.pid);
                             record.pid = "new pid";
                             {/*this.props.record.pid = "this.record.pid";*/}
                             console.log(`%c new record.pid`, `${style2}`, record.pid);
                             console.log(`%c JSON.stringify(record)`, `${style1}`, JSON.stringify(record));
                             {/*{"pname":"001","pid":"new pid","lversion":"v1","rmenu":"关联1"}*/}
                             {/* return(
                                 <SignUpDialog datas={record}/>
                             ); */}
                        }
                    } >
                        {/* {index} */}
                        {/* <SignUpDialog data={record}/> */}
                        <EM data={record} >
                            <span>{text}编辑</span>
                        </EM>
                    </a>
                );
            }
        )
    }
];

// {pname, pid, lversion, rmenu} ===  record

// rowKey	表格行 key 的取值,可以是字符串或一个函数
const data = [
    {
        pname: "001",
        pid: "产品定义 !A1",
        lversion: "v1",
        rmenu: "关联1"
    },
    {
        pname: "002",
        pid: "产品定义 !A1",
        lversion: "v2",
        rmenu: "关联2"
    },
    {
        pname: "003",
        pid: "产品定义 !A1",
        lversion: "v3",
        rmenu: "关联3"
    }
];


// 通过 rowSelection 对象表明需要行选择 

const rowSelection = {
    onSelect: function(record, selected, selectedRows) {
        // (record, selected, selectedRows) === object, boolean, object 
        console.log(`record = `, record);
        console.log(`selected = `, selected);
        console.log(`selectedRows = `, selectedRows);
        return(
            record = record + 'xyz'
        );
    },
    onSelectAll: function(selected, selectedRows) {
        // (selected, selectedRows) === boolean, object
        console.log(selected, selectedRows);
    }
};


class ProductManagement extends Component {
    showModal = (e) => {
        alert(e.target.value); 
    };
    render() {
        return (
            <div>
                <label>产品名称: </label>
                {/*<SignUpDialog datas={{}}/>*/}
                {/*<input list="t_type" name="terminal" />*/}
                <datalist id="t_type">
                    <option value="Fans终端"></option>
                     <option value="金融终端"></option>
                </datalist>
                <Button onClick={this.showConfirm}>
                    查询
                </Button>
                <Button onClick={this.showConfirm}>
                    添加
                </Button>
                <Table
                    columns={columns}
                    dataSource={data}
                    rowKey={data => data.pname}
                    rowSelection={rowSelection}
                    size="small"
                    bordered={false}
                    loading={false}
                    onChange={() => alert(`changed!`)}
                />
            </div>
        );
    }
}

export {ProductManagement};
export default ProductManagement;

@xyzdata
Copy link
Author

xyzdata commented Jul 12, 2017

Flex Layout

http://weipan.ketongtx.com/microtrade/static/crm/index.html#/stock

{...formItemLayout}

        const formItemLayout = {
            labelCol: {
                xs: { span: 24 },
                sm: { span: 8 }
            },
            wrapperCol: {
                xs: { span: 24 },
                sm: { span: 16 }
            }
        };

                        <FormItem
                            label={<span className="left-spaces">角色编码:</span>}
                            {...formItemLayout}
                            >
                            {
                                getFieldDecorator('roleCode', {
                                    initialValue: record.pname,
                                    rules: [{ required: false, message: '角色编码' }],
                                })
                                (
                                    <Input 
                                        prefix={<Icon type="user" style={{ fontSize: 13 }} />} 
                                        type="number" 
                                        placeholder="角色编码" 
                                        />
                                )
                            }
                        </FormItem>

@xyzdata
Copy link
Author

xyzdata commented Jul 12, 2017

http://weipan.ketongtx.com/microtrade/static/crm/index.html?#/Help

666666 2017-01-08 666666.com 6 编辑

@xyzdata
Copy link
Author

xyzdata commented Jul 12, 2017

react events & forms

https://facebook.github.io/react/docs/events.html#form-events

onChange, onInput, onSubmit

https://facebook.github.io/react/docs/forms.html

ES6

Computed_property_names

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Object_initializer#计算的属性名

var i = 0;
var a = {
  ["foo" + ++i]: i,
  ["foo" + ++i]: i,
  ["foo" + ++i]: i
};

a;
// Object {foo1: 1, foo2: 2, foo3: 3}

state-updates-are-merged

https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-are-merged

Uncontrolled Components

https://facebook.github.io/react/docs/uncontrolled-components.html

Controlled Components

https://facebook.github.io/react/docs/forms.html#controlled-components

The Data Flows Down

父组件子组件都不能知道某个组件是有状态还是无状态
并且它们不应该关心它是否被定义为一个函数或一个

A component may choose to pass its state down as props to its child components:

组件可以选择将其状态作为道具传递给其子组件:

https://facebook.github.io/react/docs/state-and-lifecycle.html#the-data-flows-down

<h2>It is {this.state.date.toLocaleTimeString()}.</h2>

<FormattedDate date={this.state.date} />

This is commonly called a "top-down" or "unidirectional" data flow.

这通常被称为“自上而下”或“单向”数据流。

Any state is always owned by some specific component, and any data or UI derived from that state can only affect components "below" them in the tree.

任何状态始终由某个特定组件所有,并且从该状态导出的任何数据或UI只能影响树中“下面”的组件。

@xyzdata
Copy link
Author

xyzdata commented Jul 12, 2017

redux-store-methods

image

@xyzdata
Copy link
Author

xyzdata commented Jul 12, 2017

redux & service-worker.js

The script has an unsupported MIME type ('text/html'). :3000/service-worker.js

facebook/create-react-app#658

webpack/webpack-dev-server#326

w3c/ServiceWorker#915

redux-service-workers-error

@xyzdata
Copy link
Author

xyzdata commented Jul 12, 2017

@n3tr

Awesome, it works!

Chrome Dev Tools -> Application -> Service Worker

  1. unregister

  2. refresh the page

@xyzdata
Copy link
Author

xyzdata commented Jul 12, 2017

创建 Store

https://github.com/zalmoxisus/redux-devtools-extension#usage

http://redux.js.org/docs/api/createStore.html

import AppReducer from './reducers';
// import {AppReducer} from './reducers';
// bugs : must be a root reducer, can not be use as a module
// reducers 处理 action, 更新 state


// 使用 reducers , 创建 Store
// const store = createStore(AppReducer);

// https://github.com/zalmoxisus/redux-devtools-extension#usage
// redux-devtools-extension

// 创建 store , createStore(reducer, [preloadedState], [enhancer])
// http://redux.js.org/docs/api/createStore.html

const store = createStore(AppReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());

/* 

(alias) createStore<any>(
reducer: <A extends Action>(state: any, action: A) => any, 
preloadedState: any,
enhancer?: (next: (reducer: <A extends Action>(state: any, action: A) => any, 
preloadedState?: any) => Store<any>) => (reducer: <A extends Action>(state: any, action: A) => any,
preloadedState?: any) => Store<any>): Store<any> (+1 overload)

import createStore

*/

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

state transition & bugs

Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor).
Render methods should be a pure function of props and state;
constructor side-effects are an anti-pattern, but can be moved to componentWillMount.

Unknown Prop Warning

https://facebook.github.io/react/warnings/unknown-prop.html

react-dom.js:18371 Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount.

react-props-function-call-error

image

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

状态更新可能是异步的

// class props & this.props.onClickFunction

class PropsTest extends React.Component{
    render() {
        return (
            <div>
                <button onClick={props.onClickFunction} >
                    Add counter
                </button>
                <p>
                    this state is 
                    <span 
                        style={{color: "#0ff", fontSize: "32px"}}
                        >
                        {this.props.counter}
                    </span>
                </p>
            </div>
        );
    };
};

// function props & no need this

const Test = (props) =>{
    return (
        <div>
            <button onClick={props.onClickFunction} >
                Add `props` counter
            </button>
            <p
                style={{color: "#0ff", fontSize: "32px"}}
                >
                {props.counter}
            </p>
        </div>
    );
};

// revState, props
// https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

class App extends React.Component{
    state = {
        counter: 1
    };
    addCounter = (e) => {
        console.log(`counter`, this.state.counter);
        console.log(`e =`, e);
        this.setState(
          (prevState, props) => (
              {
                  counter: prevState.counter + 1
              }
          )
        );
        // 状态更新可能是异步的
        setTimeout(() => {
        		console.log(`counter`, this.state.counter);
        });
    };
    render(){
        // onClickFunction={this.addCounter} , 
        // 不可以在父组件上直接调用父组件自身的方法来修改state,
        // 只可以方法通过props传递给子组件,在子组件上调用修改state的方法
        return(
            <div>
                <PropsTest 
                    onClickFunction={this.addCounter}
                    counter={this.state.counter}
                    />
                <Test 
                    onClickFunction={this.addCounter}
                    counter={this.state.counter}
                    />
            </div>
        );
    }
}


export default App;

const props = {
    name: "xgqfrms",
    age: 17
};

ReactDOM.render(
    <div>
        <App {...props}/>
    </div>
    , mountNode
);

https://jscomplete.com/repl

https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

https://facebook.github.io/react/docs/state-and-lifecycle.html#using-state-correctly

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

https://facebook.github.io/react/docs/state-and-lifecycle.html#using-state-correctly

不可以在父组件上直接调用父组件自身的方法来修改 state,

只可以方法通过 prop 传递给子组件,在子组件上调用修改 state 的方法

Bad Demo

// props is an object!


// message.text => array of objects
class MessageList extends React.Component {
    getChildren = () => {
        //
    }
    render() {
        const children = this.props.messages.map(
            (message, index) => {
                //console.log(`message = `, message);
            		console.log(`index = `, index);
                //console.log(`typeof index = `, typeof index);
                let xindex = 'id_' + index; 
                console.log(`xindex = `, xindex);
                //console.log(`typeof xindex = `, typeof xindex);
                return(
                    <Message
                        key={index}
                        text={message.text}
                        color={message.color}
                        xyzClick={this.props.xyzClick}
                    />
                );
            }
        );
        const styles = {
        		css1: {
            		color: 'red'
            },
            css2: {
            		color: '#0f0'
            }
        }
      	return(
            <div>
                children = {children}
                <hr />
                <div>
                    BAD: <br />
                    {/* this.props = {this.props} */}
                    <div style={styles.css1}>
                        this.props.children = {this.props.color}
                    </div>
                    {/* this.props.arr = {this.props.arr} */}
                    {/* this.props.obj = {this.props.obj} */}
                    <br />
                    <p style={styles.css2}>
                        Object Error, need using map items to item
                    </p>
                </div>
            </div>
        );
    }
}

// text={message.text} => message object
class Message extends React.Component {
    render() {
    		//console.log(`this.props.text = `, this.props.text);
        //console.log(`this.props.key= `, this.props.key);
        let style = `
        		color: red;
            font-size: 23px;
        `;
        if(this.props.key === undefined){
        		//alert(`smg!`);
            console.log(`%c this.props.key= \n`, style, this.props.key);
        }
        return (
            <div>
                <hr />
                this.props.key = {this.props.key}
                <br />
                this.props.text = {this.props.text}
                <br />
                this.props.color = <span style={{backgroundColor: this.props.color}}>{this.props.color}</span>
                <br />
                <Button color={this.props.color} xyzClick={this.props.xyzClick}>
                    <span style={{color: '#fff'}}>Delete</span>
                </Button>
            </div>
        );
    }
}

// props.children === <span style={{color: '#fff'}}>Delete</span> ??? 
class Button extends React.Component {
    render() {
        return (
            <button
                style={{background: this.props.color}} 
                onClick={(e) => this.props.xyzClick(e)} 
                >
                {this.props.children}
            </button>
        );
    }
}




const text = [
    {
    text: "text 1",
    color: "red"
    },
    {
    text: "text 2",
    color: "blue"
    },
    {
    text: "text 3",
    color: "grey"
    },
    {
    text: "text 4",
    color: "green"
    },
    {
    text: "text 5",
    color: "#f0f"
    }
];
const color = "green";
const ArrayTest = [1, 2, 3];
const ObjectTest = {"key": "value"};

class App extends React.Component{
    constructor(props){
        super(props);
        this.state  = {
            showSate: false
        };
    }
    setModalVisible = (value) => {
        console.log(`showSate`, this.state.showSate);
        console.log(`value`, value);
        this.setState({
            showSate: value
        });
        console.log(`showSate`, this.state.showSate);
    };
  	XC = (e) => {
      	let m = e.toString();
      	console.log(e, m);
      	return alert(`e.toString(); =\n`, m);
  	};
  render(){
      return(
          <div>
               <div>
                   <button onClick={() => console.log(`smg`)}>
                       onClick
                   </button>
                   <button onClick={()=>this.setModalVisible(true)}>
                       showModal{this.state.showSate}
                   </button>
               </div>
               <MessageList
                   messages={text}
                   color={color}
                   arr={ArrayTest}
                   obj={ObjectTest}
                   xyzClick={this.XC}/>
          </div>
      );
    }
};



export default App;

ReactDOM.render(
    <App />,
    mountNode
);

https://jscomplete.com/repl

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

在父组件上直接调用父组件自身的方法来修改 state,调用的方式不对!

() => { return ???;}

https://jscomplete.com/repl

// import React, {Component} from 'react';


class Item3 extends React.Component {
    constructor(props){
        super(props);
        this.state  = {
            showSateParent: false
        };
    }
    setModalVisibleParent = (value) => {
        this.setState({
            showSateParent: value
        });
    };
    render() {
        // const showSate = this.state.showSate;
        return (
            <div>
                <h1>行为分析</h1>
                {/* 
                不可以在父组件上直接调用父组件自身的方法来修改 state,
                只可以方法通过 prop 传递给子组件,在子组件上调用修改 state 的方法
                https://facebook.github.io/react/docs/state-and-lifecycle.html#using-state-correctly
                 */}
                <button onClick={() => console.log(`smg`)}>
                   showModalParent
                </button>
                 {/* 
                 <button onClick={this.setModalVisibleParent(true)}>
                   showModalParent
                </button>
                */}
                 {/* 
                 在父组件上直接调用父组件自身的方法来修改 state,调用的方式不对!
                 () => { return ???;} 
                 */}
                <button onClick={() => this.setModalVisibleParent(true)}>
                   showModalParent
                </button> 
            </div>
        );
    }
}

export default Item3;

ReactDOM.render(
    <div>
        <Item3 />
    </div>
    , mountNode
);

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

在父组件上直接调用父组件自身的方法来修改 state,调用的方式不对!

  1. 可以在父组件上直接调用父组件自身的方法来修改 state,调用的方式
<button onClick={() => this.setModalVisibleParent(true)}>
    showModalParent
</button> 
  1. 也可以方法通过 prop 传递给子组件,在子组件上调用修改 state 的方法 () => {}
<button onClick={this.props.onClickFunction} >
     `this` Add counter
</button>

<button onClick={props.onClickFunction} >
      Add `props` counter
</button>

demo 1

// import React, {Component} from 'react';


class Item3 extends React.Component {
    constructor(props){
        super(props);
        this.state  = {
            showSateParent: false
        };
    }
    setModalVisibleParent = (value) => {
        this.setState({
            showSateParent: value
        });
    };
    render() {
        // const showSate = this.state.showSate;
        return (
            <div>
                <h1>行为分析</h1>
                {/* 
                可以在父组件上直接调用父组件自身的方法来修改 state,
                也可以方法通过 prop 传递给子组件,在子组件上调用修改 state 的方法
                https://facebook.github.io/react/docs/state-and-lifecycle.html#using-state-correctly
                 */}
                <button onClick={() => console.log(`smg`)}>
                   showModalParent
                </button>
                 {/* 
                 <button onClick={this.setModalVisibleParent(true)}>
                   showModalParent
                </button>
                */}
                 {/* 
                 在父组件上直接调用父组件自身的方法来修改 state,调用的方式不对!
                 () => { return ???;} 
                 */}
                <button onClick={() => this.setModalVisibleParent(true)}>
                   showModalParent
                </button> 
            </div>
        );
    }
}

export default Item3;

ReactDOM.render(
    <div>
        <Item3 />
    </div>
    , mountNode
);

props.onClickFunction & this.props.onClickFunction

props & class components & function components

https://facebook.github.io/react/warnings/unknown-prop.html

https://facebook.github.io/react/docs/components-and-props.html#functional-and-class-components

stateless components & function components

https://facebook.github.io/react/docs/context.html#referencing-context-in-stateless-functional-components

https://facebook.github.io/react/docs/react-without-jsx.html

The component can either be provided as a string, or as a subclass of React.Component, or a plain function for stateless components.

组件可以作为字符串提供,也可以作为React.Component的子类提供,也可以作为无状态组件的普通函数提供。

elements & components

https://facebook.github.io/react/docs/rendering-elements.html

const element = <h1>Hello, world</h1>;

controlled Components & Uncontrolled Components

https://facebook.github.io/react/docs/forms.html#controlled-components

https://facebook.github.io/react/docs/uncontrolled-components.html

https://facebook.github.io/react/docs/lifting-state-up.html

// class props & this.props.onClickFunction

class PropsTest extends React.Component{
    constructor(props){
        super(props);
    }
    render() {
        // need this
        return (
            <div>
                <button onClick={this.props.onClickFunction} >
                    `this` Add counter
                </button>
                <p>
                    this state is 
                    <span 
                        style={{color: "#0ff", fontSize: "32px"}}
                        >
                        {this.props.counter}
                    </span>
                </p>
            </div>
        );
    };
};

// function props & no need this

// 无状态组件,函数组件

const Test = (props) =>{
    return (
        <div>
            <button onClick={props.onClickFunction} >
                Add `props` counter
            </button>
            <p
                style={{color: "#0ff", fontSize: "32px"}}
                >
                {props.counter}
            </p>
        </div>
    );
};

// this.setState((revState, props) => {})
// https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

// 有状态组件,React.Component 子类组件

class App extends React.Component{
    state = {
        counter: 1
    };
    addCounter = (e) => {
        console.log(`counter`, this.state.counter);
        console.log(`e =`, e);
        this.setState(
          (prevState, props) => (
              {
                  counter: prevState.counter + 1
              }
          )
        );
        // 状态更新可能是异步的
        setTimeout(() => {
        		console.log(`counter`, this.state.counter);
        });
    };
    render(){
        // onClickFunction={this.addCounter} , 
        // 不可以在父组件上直接调用父组件自身的方法来修改state,
        // 只可以方法通过props传递给子组件,在子组件上调用修改state的方法
        /* 
        在父组件上直接调用父组件自身的方法来修改 state,调用的方式不对!() => { return ???;} 
        */
        return(
            <div>
                <PropsTest 
                    onClickFunction={this.addCounter}
                    counter={this.state.counter}
                    />
                <Test 
                    onClickFunction={this.addCounter}
                    counter={this.state.counter}
                    />
            </div>
        );
    }
}

// 字符串组件,变量组件, element 元素

// https://facebook.github.io/react/docs/rendering-elements.html#rendering-an-element-into-the-dom

const element = <h1>Hello, world</h1>;


export default App;

const props = {
    name: "xgqfrms",
    age: 17
};

ReactDOM.render(
    <div>
        <App {...props}/>
    </div>
    , mountNode
);

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

卡片式页签 Tab Pane

Tab Page 标签页

https://ant.design/components/tabs-cn/

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

DropOption

// Warning: Failed prop type: The prop `menuOptions` is marked as required in `DropOption`, but its value is `undefined`.

import {DropOption} from '../utils/DropOption';



    {
        title: '编辑',
        dataIndex: 'edit',
        key: 'editRole',
        render: (text, record, index) => {
            const clickOK = (record) => {
                return record.pid = "new pid";
            };
            const menu = (
                <Menu>
                    <Menu.Item>
                    <a rel="noopener noreferrer" href="https://www.xgqfrms.xyz/">1st</a>
                    </Menu.Item>
                    <Menu.Item>
                    <a rel="noopener noreferrer" href="https://www.xgqfrms.xyz/">2nd</a>
                    </Menu.Item>
                    <Menu.Item>
                    <a rel="noopener noreferrer" href="https://www.xgqfrms.xyz/">3rd</a>
                    </Menu.Item>
                </Menu>
            );
            return(
                <span>
                    <DropOption 
                        onMenuClick={e => handleMenuClick(record, e)} 
                        overlay={menu}
                        menuOptions={[
                            {key: '1', name: '更新'},
                            {key: '2', name: '删除'}
                        ]} 
                    />
                    <EMC
                        data={record}
                        clickOK={clickOK}
                    >
                        <span>{text} 编辑</span>
                    </EMC>
                </span>
            );
        }
    }

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

二次封装 Dropdown

import React from 'react';
import PropTypes from 'prop-types';

import {Dropdown, Button, Icon, Menu} from 'antd';


// 二次封装 Dropdown

const DropOption = ({onMenuClick, menuOptions = [], buttonStyle, dropdownProps}) => {
    // 列出 menu 所有的 items
    const menuItems = menuOptions.map(
        (item) => {
            // console.log(`item `, item);
            // console.log(`item.key `, item.key);
            // console.log(`typeof item.key `, typeof(item.key));
            // if(item.key === "2" || item.name === "删除")
            const styles = {
                css1: {
                    color: "red", 
                    border: '1px solid red', 
                    borderRadius: '5px', 
                    textAlign: 'center'
                },
                css2: {
                    color: "#000", 
                    border: '1px solid #ccc', 
                    borderRadius: '5px', 
                    textAlign: 'center'
                }
            };
            if(item.name === "删除"){
                return(
                    <Menu.Item key={item.key} style={styles.css1}>
                        {item.name}
                    </Menu.Item>
                )
            }else{
                return(
                    <Menu.Item key={item.key} style={styles.css2}>
                        {item.name}
                    </Menu.Item>
                )
            }
        }
    );
    // Dropdown
    return (
        <Dropdown
            overlay={
                <Menu onClick={onMenuClick}>
                    {menuItems}
                </Menu>
            }
            trigger={['click']}
            {...dropdownProps}
            >
            <Button
                style={
                    {
                        border: 'none', 
                        background: '#ccc',
                        ...buttonStyle
                    }
                }
                >
                <Icon 
                    style={{marginRight: 5}} 
                    type="bars"
                />
                <Icon type="down" />
            </Button>
        </Dropdown>
    );
};

DropOption.propTypes = {
    onMenuClick: PropTypes.func,
    menuOptions: PropTypes.array.isRequired,
    buttonStyle: PropTypes.object,
    dropdownProps: PropTypes.object
};

export {DropOption};
export default DropOption;

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

date.toString().substr(0,10)

        {
            title: '创建时间',
            dataIndex: 'createTime',
            key: 'createTime',
            render: (date) => (
                // 2017-02-12 08:11:08
                // substr(begin [,end])
                // substr(10) === " 08:11:08"
                // substr(0,10) === "2017-02-12"
                date.toString().substr(0,10)
            )
        },

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

image

react-redux

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

Layout

Layout:布局容器,其下可嵌套 Header Sider Content Footer 或 Layout 本身,可以放在任何父容器中。
Header:顶部布局,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。
Sider:侧边栏,自带默认样式及基本功能,其下可嵌套任何元素,只能放在 Layout 中。
Content:内容部分,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。
Footer:底部布局,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。

https://ant.design/components/layout-cn/

https://ant.design/components/tabs-cn/

@xyzdata
Copy link
Author

xyzdata commented Jul 14, 2017

React table

React table with column sorting (asc, desc), input filtering, and row ordering

https://codereview.stackexchange.com/questions/106908/react-table-with-column-sorting-asc-desc-input-filtering-and-row-ordering

https://codepen.io/reggi/pen/KdqdMW?editors=001

2.10.6/moment.min.js, react-with-addons-0.13.3.js, 3.0.1/lodash.min.js

function recursive(collection, callback, recursiveIndexCb) {
    var indexed = (recursiveIndexCb)
        ? recursive.recursiveIndex(collection, recursiveIndexCb)
        : false;
    var meta = (recursiveIndexCb)
        ? recursive.meta(indexed)
        : false;
    function wrapper(callback) {
        return function () {
            var args = _.values(arguments);
            var id = args[1];
            var recursiveId = (this.id === 0)
                ? id.toString()
                : id + '.' + this.id;
            args.push(recursiveId);
            return callback.apply({
                'meta': meta,
                'indexed': indexed
            }, args);
        }.bind(this);
    }
    var recursed = false;
    function _recursive(collection, callback) {
        recursed = (recursed === false)
            ? 0
            : recursed + 1;
        return callback(collection, _.partialRight(_recursive, callback), wrapper.bind({'id': recursed}));
    }
    return _recursive(collection, callback);
};

recursive.compare = function (n1, n2) {
    var path1 = n1.split('.');
    var path2 = n2.split('.');
    var maxLen = Math.max(path1.length, path2.length);
    var i = 0;
    while (i < maxLen) {
        if (!path1[i] || + path1[i] < + path2[i]) {
            return -1;
        }
        if (!path2[i] || + path1[i] > + path2[i]) {
            return 1;
        }
        i++;
    }
    return 0;
};

recursive.subset = function (ids, id) {
    return _.filter(ids, function (_id) {
        var _idArr = _id.split('.');
        var idArr = id.split('.');
        var _idChop = _.take(_idArr, _idArr.length - 1).join('.');
        var idChop = _.take(idArr, idArr.length - 1).join('.');
        if (_idChop === idChop) 
            return true;
        return false;
    });
};
/* 
wrapper(function (node, id, nodes, recursiveId) {
    if (node.children) 
        recursive(node.children);
    result[recursiveId] = node;
}
 */
recursive.recursiveIndex = function (nodes, recursiveIndexCb) {
    var result = {};
    recursive.recursive(nodes, function (node, recursive, wrapper) {
        _.each(node, function (value, key, values, rId) {
            var args = _.values(arguments);
            var val = recursiveIndexCb.apply(null, args);
            result[rId] = val;
        });
    }, true);
    return result;
};

recursive.meta = function (indexed) {
    var ids = _.keys(indexed);
    return function (id, distance) {
        distance = (distance)
            ? distance
            : 1;
        ids = ids.sort(recursive.compare);
        var idIndex = ids.indexOf(id);
        var meta = {};
        meta.prev = (ids[idIndex - distance])
            ? ids[idIndex - distance]
            : false;
        meta.next = (ids[idIndex + distance])
            ? ids[idIndex + distance]
            : false;
        var idsSubset = recursive.subset(ids, id);
        var idSubsetIndex = idsSubset.indexOf(id);
        meta.prevSibling = (idsSubset[idSubsetIndex - distance])
            ? idsSubset[idSubsetIndex - distance]
            : false;
        meta.nextSibling = (idsSubset[idSubsetIndex + distance])
            ? idsSubset[idSubsetIndex + distance]
            : false
        return meta;
    };
};

var st = {};

/** ensure children or reactFragment is an array of reactElements */
st.ensureChildrenArray = function (children) {
    var results = [];
    React.Children.forEach(children, function (child) {
            results.push(child);
        });
    return results;
};

// I know this is bad practice but I'm not sure of an alternative
/** map children and clone with props assign random key */
st.cloneChildren = function (children) {
    return React.Children.map(children, function (child, i) {
        return React.addons.cloneWithProps(child, {'key': Math.random()});
    });
};

/** sorts chilren based on column property */
st.sortChildren = function (children, column, format, direction) {
    children = st.ensureChildrenArray(children);
    var results = _.sortBy(children, function (item) {
        var match = _.find(item.props.children, function (child) {
            return (child.props.column === column);
        });
        if (format) 
            return moment(match.props.children, format).toDate();
        return match.props.children;
    })
    if (direction === 'asc') 
        results = results.reverse();
    return st.cloneChildren(results);
};

/** filters array of children based on value */
st.filterChildren = function (children, filterValue, caseSensitive) {
    children = st.ensureChildrenArray(children);
    var results = recursive(children, function (children, recursion, wrapper) {
        return _.filter(children, wrapper(function (child) {
            if (typeof child.props.children !== 'string') {
                var result = recursion(child.props.children);
                return Boolean(result.length);
            } else {
                var flag = (caseSensitive)
                    ? ''
                    : 'i';
                var pattern = new RegExp(filterValue, flag);
                var value = child.props.children.match(pattern);
                return value;
            }
        }))
    });
    return st.cloneChildren(results);
};

st.objectWithOneProp = function (prop, val) {
    var temp = {};
    temp[prop] = val;
    return temp;
};

st.invokeSort = function (column, dateFormat) {
    return function (event) {
        var data = {};
        data.stateCycle = ['desc', 'asc'];
        data.column = 'header_' + column;
        data.headerState = this.state[data.column];
        data.index = _.indexOf(data.stateCycle, data.headerState);
        data.nextState = (data.index !== (data.stateCycle.length - 1))
            ? data.stateCycle[data.index + 1]
            : data.stateCycle[0];
        data.setState = st.objectWithOneProp('header_' + column, data.nextState);
        data.sortedChildren = st.sortChildren(this.refs.tbody.state.children, column, dateFormat, data.headerState);
        this.setState(data.setState)
        this.refs.tbody.setState({children: data.sortedChildren});
    }.bind(this);
};

st.invokeFilter = function (event) {
    var data = {};
    data.filteredChildren = st.filterChildren(this.refs.tbody.props.children, event.target.value, false);
    this.refs.tbody.setState({children: data.filteredChildren});
};

st.onMountOrder = function (elm) {
    return _.sortBy(elm.state.children, function (item) {
        return item.props.column;
    });
};



var StatefulChildren = React.createClass({
    displayName: 'StatefulChildren',
    propTypes: {
        children: React.PropTypes.node,
        element: React.PropTypes.string,
        defaultElement: React.PropTypes.string,
        modify: React.PropTypes.array || React.PropTypes.func
    },
    getDefaultProps: function () {
        return {defaultElement: 'span'};
    },
    getInitialState: function () {
        return {children: this.props.children};
    },
    componentWillMount: function () {
        if (typeof this.props.modify === 'function') {
            this.setState({
                children: this.props.modify(this)
            })
        } else if (this.props.modify) {
            this.props.modify.forEach(
                function (mod) {
                    this.setState({children: mod(this)})
                }.bind(this)
            );
        }
    },
    render: function () {
        var props = _.omit(this.props, ['element', 'defaultElement', 'children']);
        if (this.props.element) {
            return React.createElement(this.props.element, props, this.state.children);
        } else if (typeof this.state.children === 'string' || !React.isValidElement(this.state.children)) {
            return React.createElement(this.props.defaultElement, props, this.state.children);
        } else {
            return this.state.children;
        }
    }
})

var Table = React.createClass({
    getInitialState: function () {
        return {
            'header_date': 'desc',
            'header_name': 'desc'
        }
    },
    render: function () {
        return (
            <div>
                <input type='text' onChange={st.invokeFilter.bind(this)}/>
                <table>
                    <StatefulChildren element='thead' modify={[st.onMountOrder.bind(this)]}>
                        <th column='date' onClick={st.invokeSort.bind(this)('date', 'MMMM Do, YYYY')}>Date</th>
                        <th column='name' onClick={st.invokeSort.bind(this)('name')}>Name</th>
                    </StatefulChildren>
                    <StatefulChildren element='tbody' ref='tbody'>
                        <StatefulChildren element='tr' modify={[st.onMountOrder.bind(this)]}>
                        <td column='name'>Velma</td>
                        <td column='date'>October 28th, 2014</td>
                        </StatefulChildren>
                        <StatefulChildren element='tr' modify={[st.onMountOrder.bind(this)]}>
                        <td column='date'>October 4th, 2015</td>
                        <td column='name'>Julie</td>
                        </StatefulChildren>
                        <StatefulChildren element='tr' modify={[st.onMountOrder.bind(this)]}>
                        <td column='date'>December 1th, 2011</td>
                        <td column='name'>Becky</td>
                        </StatefulChildren>
                        <StatefulChildren element='tr' modify={[st.onMountOrder.bind(this)]}>
                        <td column='date'>January 4th, 2015</td>
                        <td column='name'>Ashley</td>
                        </StatefulChildren>
                    </StatefulChildren>
                </table>
            </div>
        )
    }
});

// React.render(<Table/>, document.getElementById('container'));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment