SOURCE

console 命令行工具 X clear

                    
>
console
/****
 * react-control-center是什么?
 * react-control-center是一个专门为react定制的,更加智能更加强大却更简单的状态管理框架
 */

const CcFragment = cc.CcFragment;

//启动cc,声明一个store, 注意哦,这里我们示意非模块化的方式启动,
//这种方式,只能使用cc内置的两个store模块,$$default 和 $$global
cc.startup(
    {
        isModuleMode: true,//声明cc以模块化的方式启动,这样cc就允许在默认的$$default、$$global模块之外,定义更多的模块了
        store: {//模块化下,store的第一层key表示模块名称
            $$default: {
                name: 'this name come from $$default state',
                address: 'BJ',
                hobby: 'watching film',
            },
            foo: {//声明一个新的foo模块
                name: 'this name come from foo state',
                //我们来多个几个属性
                address: 'SH',
                hobby: 'coding',
            },
            //我们再来定义一个新的模块bar
            bar: {
                secret: 'wow bar'
            },
        },
        //reducer对象的key表示的是reducer各个模块的名称,我们可以默认和store模块同名
        reducer: {
            //我们为$$default定义一个方法吧,这个方法可以是普通函数,也可以是async函数,或者generator函数
            $$default: {
                async changeName({ payload: name }) {
                    return { name };
                },
            },
            //我们来定义一个新的reducer module名为foo,
            foo: {
                async changeName({ payload: name }) {
                    //为了证明调用了foo,我们加个前缀f
                    return { name: `f${name}` };
                },
                changeHobby({ payload }) {
                    //$$domDispatch的payload可以解构出来的key如下
                    const { event, value, dataset } = payload;
                    return { hobby: value }
                },
                //reducer function里一定要返回一个新的片段state吗?可以不用哦,可以调用其他的reducer方法,
                // 所以一个reducer方法时可以组合其他多个reducer方法,且本身不返回任何值的哦
                clearName() {
                    return { name: '' };
                },
                clearAddress() {
                    return { address: '' };
                },
                clearHobby() {
                    return { hobby: '' };
                },
                async clearAll({ dispatch }) {
                    //一个一个清除, 注意这里的dispatch默认自带的module是触发$$dispatch时的那个实例所指定的module
                    //await dispatch('/foo/clearName');
                    //await dispatch('/foo/clearAddress');
                    //await dispatch('/foo/clearHobby');

                    //一起执行
                    Promise.all([
                        dispatch('/foo/clearName'),
                        dispatch('/foo/clearAddress'),
                        dispatch('/foo/clearHobby'),
                    ]);
                }
            },
            bar: {
                changeSecret({ payload: { value: secret } }) {
                    return { secret };
                }
            }
        },
        sharedToGlobalMapping: {
            bar: {
                //将bar的secret映射到$$global里,别名叫secret,别名是任意的只要不和$$global模块里的已有key重复就可以了
                'secret': 'secret',
            }
        },
        //这里配置一个错误处理函数,简单的将所有的cc错误打印一下
        errorHandler: err => console.log(err),
    }
);

function changeAddress(address, suffix) {
    return { address: `${address}${suffix}` }
}

//这真的只是一个普通的Hello
class Hello extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            name: 'normol component',
        };
    }
    changeName = (e) => {
        const name = e.currentTarget.value;
        //this.setState({ name: e.currentTarget.value });

        //让我们换一种写法来改变状态,this.$$dispatch(action:Action);
        //module表示要去修改那个state module的数据,
        //reducerModule表示使用哪个recuder module下的函数map
        //type表示使用函数map下的函数名为type值的函数去执行
        //payload就是要传递的数据啦
        //  this.$$dispatch({module:'$$default',reducerModule:'$$default',type:'changeName',payload:name});

        //因为我们的当前实例就是属于$$default模块,目标reducer module也和$$default重名的,所以可以简写为
        //  this.$$dispatch({type:'changeName',payload:name});

        //再换一种方式写$$dispatch, this.$$dispatch(typeDescriptor:string, payload:any)
        //this.$$dispatch('changeName', name);
        //等同于写, typeDescriptor字符串形如 (stateModuleName)/(reducerModuleName)/(functionName)
        //  this.$$dispatch('$$default/$$default/changeName', name);

        //基于typeDescriptor写法,如果我们想用foo reducer module的changeName方法去修改 $$default state module的值该怎么写呢?
        //  this.$$dispatch('$$default/foo/changeName', name);
        //因为实例属于$$default模块,所以我们可以省略写模块名,只写recuder模块名
        //typeDescriptor字符串形如 /(reducerModuleName)/(functionName), 此时注意哦第一个斜杠不能少
        //  this.$$dispatch('/foo/changeName', name);

        //如果我们少了第一个斜杠表示什么呢?
        //此时 typeDescriptor字符串形如 (stateModule and reducerModuleName)/(functionName),
        //既表示state module,也表示reducer module了,所以如果你规划reducer的模块时候,刻意和state模块保持一致命名,就可以这样写了
        //  this.$$dispatch('foo/changeName', name);
        //现在我们这样写,看到console报错了,因为这种写法现在表示目标state module是foo,用foo reducer module下的changeName去生成新的片段状态
        //我们现在去定义foo模块吧,

        //让都以Hello为输入注册成为了不同的cc组件各自修改自己所属模块的数据,但是都要foo reducer的changeName方法
        this.$$dispatch('/foo/changeName', name);
    }
    changeAddress = (e) => {
        const address = e.currentTarget.value;
        //这里我们不走$$dispatch, 直接使用$$effect吧, this.$$effect(module:string, userFn:Function, ...args)
        //同样userFn可以是普通函数,生成器函数,async函数哦
        //this.$$effect(this.cc.ccState.module, changeAddress, address, 'e');

        //$$effect第一位参数必须指定module,如果我总是想改变当前实例所属的module的state呢,$$invoke来满足你
        this.$$invoke(changeAddress, address, 'e');
    }
    render() {
        console.log('@@@' + this.cc.ccState.ccClassKey);
        const { name, address, hobby } = this.state;
        //我们想在这里观察到bar模块的secret变化怎么办呢?
        //我们知道,cc组件都能够观察自己所属模块的state变化,且所有cc组件都能够通过globalStateKeys观察$$global模块里的state变化
        //所以接下来我们将在startup里使用sharedToGlobal,将bar模块的secret映射到$$global里

        //注意哦,这里能取到secret,因为cc实例的state是由它观察的module state,加上global state,再加上自己的state合并出来的
        const { secret } = this.state;
        return (
            <div style={{ borderBottom: '3px solid green', marginTop: '6px' }}>
                hello,
              my name is <span>{name}</span>,
              my address is <span>{address}</span>,
              my hobby is <span>{hobby}</span>,
              bar secret is <span>{secret}</span>,
               <hr />
                <input value={name} onChange={this.changeName} />
                <input value={address} onChange={this.changeAddress} />
                {/* 这里我们直接使用$$domDispatch哦 */}
                {/* data-cct表示type */}
                {/* data-ccm表示module,不指定的话就默认为当前实例所属的module */}
                {/* data-ccrm表示reducder module,不指定的话等同于当前实例的module */}
                <input data-cct="changeHobby" data-ccrm="foo" value={hobby} onChange={this.$$domDispatch} />
                <button data-cct="clearAll" data-ccrm="foo" onClick={this.$$domDispatch}>清除所有</button>
                <hr />
            </div>
        )
    }
}
//注册为cc组件,不声明属于任何模块,cc默认该组件属于$$default模块,当然
//设定sharedStateKeys为*,表示共享所属模块的所有key变化(这里指的就是$$default罗)
//设定globalStateKeys为*,表示共享$$global模块的所有key变化
const CcHello1 = cc.register('Hello1', { module: '$$default', sharedStateKeys: '*', globalStateKeys: '*' })(Hello);

//我们发现输入input框没有任何变化,因为CcHello1的实例读取的$$default模块的数据哦,我们再来注册一个cc组件属于foo模块
//注意哦,我们在CcHello1的input框里输入值,却改变了CcHello2,
//是因为 'foo/changeName' 描述的是目标state module是foo,用foo reducer的changeName方法
const CcHello2 = cc.register('Hello2', { module: 'foo', sharedStateKeys: '*', globalStateKeys: '*' })(Hello);

class Bar extends React.Component {
    render() {
        const { secret } = this.state;
        return <input value={secret} data-cct="changeSecret" onChange={this.$$domDispatch} />
    }
}
const CcBar = cc.register('Bar', { module: 'bar', sharedStateKeys: '*' })(Bar);

/****
 如果讨厌从数据state取上这种设计,我想让我的state保持纯洁如初的感觉怎么办?
 因为我们最初的理解是state是组件自己的临时状态,模块的公共状态是由props传递下来的啊!!!
 而且所有cc组件都属于某一个模块,同时所有cc组件能都能观察$$global模块的变化,
 意味着cc组件最多只观察两个模块的状态变化
 我想观察多个模块的变化怎么办,难道我要把所有的key都通过sharedToGlobalMapping映射到$$global里?
 stateToPropMapping来帮你搞定一切
*/
class Zzk extends React.Component {
    render() {
        //stateToPropMapping映射的数据可以从$$propState取出来
        //任何key发生变化,cc都会通知该实例渲染
        const { foo_name, bar_secret } = this.$$propState;
        return (
            <div>
             name of foo is <span>{foo_name}</span>,
             secret of bar is <span>{bar_secret}</span>,
            </div>
        )
    }
}
const CcZzk = cc.register('Zzk', {
    stateToPropMapping: {
        'foo/name': 'foo_name',
        'bar/secret': 'bar_secret',
    }
})(Zzk);
//如果我想多加上观察$$default下的name呢?为了避免key重复,起别名好累,而且我想观察n个模块所有的key,
//每一个都写一遍吗?
let stateToPropMapping = {
    '$$default/name': 'default_name',
    'foo/name': 'foo_name',
    'bar/secret': 'bar_secret',
}
//可以这样写了哦
stateToPropMapping = {
    '$$default/*':'',
    'foo/*':'',
    'bar/*': '',
}

const CcZzk2 = cc.connect('Zzk2', stateToPropMapping, {isPropStateModuleMode:true})(
    class extends React.Component {
        render() {
            //现在可以按模块去取值了
            const { $$default, foo, bar } = this.$$propState;
            return (
                <div>
                    name of default is <span>{$$default.name}</span>,
                    name of foo is <span>{foo.name}</span>,
                    secret of bar is <span>{bar.name}</span>,
            </div>
            )
        }
    }
);



class App extends React.Component {
    render() {
        return (
            <div>
                <div style={{border:'6px solid red', padding:'6px'}}>
                     here show cc's hook
                    <CcFragment connect={{'foo/*':''}} render={({hook, propState})=>{
                        const [count, setCount] = hook.useState(0);
                        return (
                            <div>
                                <span>{propState.foo.name}</span><br />
                                <button onClick={()=>setCount(count+1)}>add, now is:{count}</button>
                                <button onClick={()=>setCount(count-1)}>minus, now is:{count}</button>
                            </div>
                        );
                    }}/>
                </div>
                <CcHello1 />
                <CcHello2 />
                <CcBar />
                <CcZzk />
                <CcZzk2 />
            </div>
        );
    }
}

ReactDOM.render(<App />, document.getElementById('app'));
<!DOCTYPE html>
<html lang="en">
  
  <head>
    <meta charset="UTF-8" />
    <title>
      react.js 练习模板
    </title>
    <script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js">
    </script>
    <script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js">
    </script>
    <!--引入react-control-center-->
    <!-- react-control-center是一个专门为react定制的,更加智能更加强大却更简单的状态管理框架 -->
    <script src="https://www.zzkai.com/js/react-control-center-1.1.74.min.js">
    </script>
  </head>
  
  <body>
    <div id="app">
    </div>
  </body>

</html>
span{
  padding:2px 6px;
  background-color: #EF978A;
  color:white;
}

input{
    width:280px;
}

本项目引用的自定义外部资源