{"id":16385755,"url":"https://github.com/aaaaash/learn-react","last_synced_at":"2026-05-24T04:30:17.036Z","repository":{"id":100795590,"uuid":"61707385","full_name":"Aaaaash/learn-React","owner":"Aaaaash","description":"React学习","archived":false,"fork":false,"pushed_at":"2016-08-17T06:15:56.000Z","size":5584,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-15T07:41:39.540Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Aaaaash.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-06-22T09:41:03.000Z","updated_at":"2016-07-17T13:01:32.000Z","dependencies_parsed_at":"2023-03-23T15:03:07.563Z","dependency_job_id":null,"html_url":"https://github.com/Aaaaash/learn-React","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aaaaash%2Flearn-React","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aaaaash%2Flearn-React/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aaaaash%2Flearn-React/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aaaaash%2Flearn-React/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Aaaaash","download_url":"https://codeload.github.com/Aaaaash/learn-React/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240136988,"owners_count":19753645,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T04:15:15.838Z","updated_at":"2026-05-24T04:30:16.968Z","avatar_url":"https://github.com/Aaaaash.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"#React入门\n\nReact是Facebook内部开源出来的一套前端UI开发框架，现在来讲React不仅仅是js框架本身，更是一套完整的前端开发生态体系\u003cbr/\u003e\n* React.js\n* ReactRenders: ReactDOM / ReactServer / ReactCanvas\n* Flux模式\n* React开源组件\n* React Native\n* GraphQi+Relay\n\n##React中的基本概念\n###React.js\nReact.js是React的核心库，在应用中必须先加载核心库\u003cbr/\u003e\n###ReactDOM.js\nReactDOM.js是React的DOM渲染器，React将核心库和渲染器分离开，为了在web页面中显示开发的组件，需要调用ReactDOM.render方法，第一个参数是React组件，第二个参数是HTMLElement\u003cbr/\u003e\n###JSX语法\nJSX是React自定义的一种JavaScript语法，最终会被转化为js运行在页面中\u003cbr/\u003e\n###组件\n组件是React的核心概念，页面当中的所有元素都是通过React组件来表达，React的代码绝大多数都是在开发React组件\u003cbr/\u003e\n###VIRTUAL DOM\n虚拟DOM，React抽象出来的虚拟DOM树，可以避免频繁的操作DOM，提高运行性能的关键\u003cbr/\u003e\n###单项数据流\nReact 应用的核心设计模式，数据流向自顶向下\u003cbr/\u003e\n##Hello World\n\n\u003e例子详见React-helloworld-demo\u003cbr/\u003e\n\n```JavaScript\n    var Hello=React.createClass({\n        render:function(){\n            return \u003cdiv\u003eHello {this.props.name}\u003c/div\u003e\n        }\n    });\n    ReactDOM.render(\n        \u003cHello name=\"World!\"/\u003e,\n        document.getElementById('example');\n    )\n```\n以上就是JSX语法，组件内部写法和HTML一样，直接在函数中写xml标签\n##React独特之处\n* 组件的组合模式\u003cbr/\u003e\n* 单向数据流的设计\u003cbr/\u003e\n* 虚拟DOM高效的性能\u003cbr/\u003e\n* 分离的设计\u003cbr/\u003e\n\n###组件的组合模式\n\u003e组合模式也就是说在React中所有标签无论大小都看做一个组件，任意组件相互组合也会形成一个大组件，基于组件构建整个web应用\n\n组合模式的优点：\u003cbr/\u003e\n* 构建可以重用的组件，组件开发能够形成公司的组件库，每个业务的开发都可能会累计可重用的组件\u003cbr/\u003e\n* 无学习障碍，天然符合HTML的结构\u003cbr/\u003e\n* 组合模式简单有效，能够构建简单的web应用也能构建大型的web应用\u003cbr/\u003e\n* 源码可维护性高，很多大型的web应用因为复杂的业务逻辑导致无法快速响应业务需求，可维护性很低\u003cbr/\u003e\n\n###单项数据流的设计\nReact的单向数据流设计可以让前端迅速的定位bug所在，页面的UI和数据对应是唯一的，可以通过定位数据变化快速的定位页面bug\u003cbr/\u003e\n###高效的性能\nvirtual DOM的概念，基于virtualDOM算法，可以让只有需要改变的dom元素才进行重新渲染\u003cbr/\u003e\n###分离的框架设计\n现版本的React已经把核心库React.js和ReactDOM分离，这就意味着React不仅仅能够在web端工作，也有可能会在服务器端工作\u003cbr/\u003e\n###React应用范围\n* web端应用\n* 原生应用（ISO,android，Native）\n* Node JS服务端渲染\u003cbr/\u003e\n\n####Web端应用\nWeb应用是React的出发点，我们可以通过React构建简单的web端应用，甚至是大型的web应用。同时在web端，还可以用React实现数据可视化，游戏等等。。。\u003cbr/\u003e\n####原生应用\n基于facebook开源的ReactNative,我们可以使用JSX语法构建ios甚至是android端应用\u003cbr/\u003e\n####服务端渲染\nReact 除了在 Web 和 Native 环境以外， 也可以在服务器端渲染出 HTML。\u003cbr/\u003e\n\n##JSX语法\n\u003eJSX 的写法在组件的组合和属性的传递上提供了非常灵活的解决方案\n\n###JSX本质\n创建JSX语法的本质目的是为了使用基于XML的方式表达组件的嵌套，保持和HTML一致的结构，语法上除了在描述组件上比较特别以外，其他地方都和原生JavaScript没有太大区别，且JSX最终都会编译为原生的JavaScript语法\u003cbr/\u003e\n\n###xml规则\nJSX组件嵌套的规则和XML基本一致\u003cbr/\u003e\n####嵌套规则\n\u003e标签可以任意的嵌套\n\n```JavaScript\n    function render(){\n        return \u003cp\u003e\n            text context\n            \u003cul\u003e\n                \u003cli\u003e\u003c/li\u003e\n                \u003cli\u003e\u003c/li\u003e\n                \u003cli\u003e\u003c/li\u003e\n            \u003c/ul\u003e\n        \u003c/p\u003e\n    }\n```\n####标签闭合\n标签必须严格闭合，否则无法编译通过\u003cbr/\u003e\n```JavaScript\n    function render(){\n        return \u003cinput type=\"text\"/\u003e\n    }\n    function render(){\n        return \u003cp\u003e\u003c/p\u003e\n    }\n```\n###JSX组件\nJSX组件分为`HTML原生组件`和`自定义组件`\u003cbr/\u003e\n```JavaScript\n    function (){\n        return \u003cp\u003e\u003c/p\u003e\n    }\n    function(){\n        return \u003cul\u003e\n                \u003cli\u003e\u003c/li\u003e\n                \u003cli\u003e\u003c/li\u003e\n                \u003cli\u003e\u003c/li\u003e\n               \u003c/ul\u003e\n    }\n```\nReact组件就是自定义组件\u003cbr/\u003e\n```JavaScript\n    function CustomCompont=React.createClass({\n        render:function(){\n            return \u003cdiv\u003eCustomCompont\u003c/div\u003e\n        }\n    });\n    function render(){\n        return \u003cp\u003e\u003cCustomCompont/\u003e\u003c/p\u003e\n    }\n```\n###组件属性\n和html一样，JSX中的组件也有属性，传递属性的方式也基本相同\u003cbr/\u003e\n对于HTML组件：\u003cbr/\u003e\n\n```JavaScript\n    function render(){\n        return \u003cp title=\"title\"\u003eHello World!\u003c/p\u003e\n    }\n```\n\n而如果是React组件，可以自定义属性，传递自定义属性的方式也基本相同\u003cbr/\u003e\n\n```JavaScript\n    function render(){\n        return \u003cp\u003e\u003cCustomComponent customProps=\"data\"/\u003e\u003c/p\u003e\n    }\n```\n\n属性即可以是字符串，也可以是任意的JavaScript变量\u003cbr/\u003e\n而传递属性的方式是变量用花括号包起来\u003cbr/\u003e\n\n```JavaScript\n    function render() {\n        var data = {a: 1, b:2};\n        return \u003cp\u003e \u003cCustomComponent customProps={data}/\u003e \u003c/p\u003e\n    }\n```\n\n\u003e有一个区别是，在写JSX的时候，所有的属性都是`驼峰命名法`\n\n```JavaScript\n    function render(){\n        return \u003cdiv className=\"...\"\u003e\n            \u003clabel htmlFor=\"..\"\u003e\u003c/label\u003e\n            \u003cinput onChange=\"\"/\u003e\n        \u003c/div\u003e\n    }\n```\n驼峰式是JavaScript的标准写法，并且React底层是将属性直接对应到原生DOM属性，而原生DOM的属性其实就是驼峰式写法，而这里class和for是js的关键字，所以在JSX中这两个属性应该写成`className`和`htmlFor`\u003cbr/\u003e\n\n除此之外比较特殊的地方是 data-* 和 aria-* 两类属性是和 HTML 一致的。\u003cbr/\u003e\n\n###JSX花括号\n####显示文本\n有时候我们需要将js中的文本直接显示，做法和变量一样用花括号\u003cbr/\u003e\n```JavaScript\n    function render(){\n        var text=\"Hello World!\";\n        return \u003cp\u003e{text}\u003c/p\u003e\n    }\n```\n####运算\n花括号里边除了变量以外，还可以是一段js表达式，可以利用花括号做简单的运算\u003cbr/\u003e\n```JavaScript\n    function render(){\n        var text=text;\n        var isTrue=false;\n        var arr=[1,2,3];\n        return \u003cp\u003e\n            {text}\n            {isTrue?'true':'false'}\n            {arr.map(function(){\n                return \u003cspan\u003e{it}\u003c/span\u003e\n                })}\n        \u003c/p\u003e\n    }\n```\n###JSX注释\n注释的写法与原生js基本一致\u003cbr/\u003e\n```JavaScript\n    function render(){\n        /*这里是注释内容*/\n    }\n```\n###限制规则\nrender方法返回的组件必须有且只有一个根组件\u003cbr/\u003e\n\n    function render(){\n        return \u003cP\u003e\u003c/p\u003e\n        \u003cp\u003e\u003c/p\u003e\n        //无法编译通过，JSX会显示编译错误\n    }\n\n###组件命名空间\nJSX可以通过命名空间的方式使用组件，通过命名空间的方式可以解决相同名称不同用途的组件\u003cbr/\u003e\n```JavaScript\n    function render(){\n        return \u003cdiv\u003e\n        \u003cCustomCompont1.subElement/\u003e\n        \u003cCustomCompont2.subElement/\u003e\n        \u003c/div\u003e\n    }\n```\n###JSX的编译方式\nJSX最终会被解释成原生js的语法，而且实际上如果愿意的话可以直接写js的语法，但是JSX的开发体验可能会更好一点\u003cbr/\u003e\nJSX的编译方式有两种\u003cbr/\u003e\n* 在HTML中引入babel编译器，如一开始HelloWorld中的`browser.min.js`\n* 离线JSX编译，通过babel编译JSX\n###JSX到js的转化\n例如一开始的Hello World转化为js的代码如下\u003cbr/\u003e\n```JavaScript\n    var Hello=React.createClass({\n        displayName:'Hello',\n        render:function(){\n            return React.createElement('div',null,'Hello',this.props.name);\n        }\n        });\n    ReactDOM.render(\n        React.createElement(Hello,{name:'World!'}),\n        document.getElementById('container')\n        )\n```\n\u003e\u003cHello/\u003e==\u003eReact.createElement(Hello,...)\n\n基本可以得知，React中组件就是一个对象\u003cbr/\u003e\n\n##React组件\n###React组件介绍\n在React中组件是第一元素，是React的基础，一个React应用就是由多个组件组合而成的\u003cbr/\u003e\n\n###创建一个组件\n创建一个组件，需要调用React.createClass方法，传入一个对象作为参数，且必须有一个render方法，render方法则返回整个组件的结构，render的返回值有且只能有一个组件实例，或者返回null/false，当返回null/false时，React内部通过\u003cnoscript/\u003e标签替换！\u003cbr/\u003e\n\n    ```JavaScript\n    var MyComponte=React.createClass({\n        render:function(){\n            return \u003cp\u003e\u003c/p\u003e\n        }\n        });\n    ```\n\n####组件的命名空间\nReact.createClass方法生成的组件实际上是一个JavaScript对象，也可以设置命名控件组件\u003cbr/\u003e\n    ```JavaScript\n    MyComponent.SubComponent=React.createClass({....})\n    MyComponent.SubComponent.Sub=React.createClass({....})\n    ```\n\n组件较多的情况下，可以借助命名空间的方式解决组件名称冲突的问题\u003cbr/\u003e\n\n####无状态组件\n还有一种创建组件的方式是通过一个普通函数返回组件\u003cbr/\u003e\n\n    function StatesComponent(props){\n        return \u003cdiv\u003eHello {props.name}\u003c/div\u003e\n    }\n\n这样创建的组件内部不会维护状态，React内部也不会有一个对应的组件实例，并且也没有生命周期`hook`\n\n###组件的渲染\n当创建好了一个组件以后，将这个组件渲染到页面上一共有两个步骤\u003cbr/\u003e\n* 首先页面中需要有一个父级容器来容纳这个组件，事先在HTML中定义一个元素，并设置id属性\n* JSX中调用ReactDOM.render方法，第一个参数为需要插入的组件，第二个参数就是之前定义的这个父级DOM元素\n\n    ```html\n    //html中定义父级div\n    \u003cdiv id=\"app\"\u003e\u003c/div\u003e\n    ```\n    ```JavaScript\n        //自定义组件\n        var MyComponent=React.createClass({\n            render:function(){\n                return \u003cp\u003e.....\u003c/p\u003e;\n            }\n            });\n            //调用render方法渲染组件到容器中\n            ReactDOM.render(\n                \u003cMyComponent/\u003e,\n                document.getElementById('app')\n                );\n    ```\n有一些问题需要注意:\u003cbr/\u003e\n* React可以渲染组件到多个元素，并且是任意位置的元素\n* 程序运行中可以动态的调用render方法\n* 数据修改后不需要重新调用render方法\n\n###组件状态State\nReact中每个组件可以存储自己的当前状态，React的渲染结果是由组件属性和状态共同决定的，状态和属性(props)的区别是：\u003cbr/\u003e\n* 状态维护在组件的内部\n* 属性是由外部控制\n\n控制状态的API分比为：\u003cbr/\u003e\n* this.state:组件的当前状态\n* getInitialState：获取组件的初始状态，在组件加载的时候会被调用一次，返回值给this.state作为初始值\n* this.setState:\n    * 组件状态改变时，可以通过this.setState修改状态\n    * setState支持按需修改，也就是说可以传入一个key只修改一个状态\n    * 每次调用setState会导致重渲染调用render方法\n    * 直接修改state 不会重新渲染组件\n\n```JavaScript\nvar Switch=React.createClass({\n    //定义Switch组件的初始状态，初始为关闭\n    getInitialState:function(){\n        return {\n            open:false\n        }\n    },\n    //通过this.state获取当前状态\n    render:function(){\n        console.log('render switch component');\n        var open=this.state.open;\n        return \u003clabel className=\"switch\"\u003e\n            \u003cinput type=\"checkbox\" checked={open}/\u003e\n        \u003clabel/\u003e\n    },\n    //通过setState修改状态\n    //setState 过后会 React 会调用 render 方法重渲染 input 组件状态\n    toggleSwitch:function(){\n        var open=this.state.open;\n        this.setState({\n            open:!open\n            });\n    }\n});\n```\n\n\n###组件属性props\nReact可以传递属性给组件，方法和html中差不多，可以通过this.props获取组件属性\u003cbr/\u003e\n控制属性的API：\u003cbr/\u003e\n* this.props:获取属性值\n* getDefaultProps:获取默认属性对象，会被调用一次，返回值会被缓存起来，当组件被 实例化后如果传入的属性没有值，则会返回默认值\n* this.props.children:子节点属性\n* propsTypes:属性类型检查\n\n以一个待办事项列表组件为例：\u003cbr/\u003e\n```JavaScript\n    var TodoItem=React.createClass({\n        render:function(){\n            var props=this.props;\n            return \u003cdiv className=\"todo-item\"\u003e\n                \u003cspan className=\"todo-item__name\"\u003e{props.name}\u003c/span\u003e\n            \u003c/div\u003e\n        }\n    });\n    ReactDOM.render(\n        \u003cTodoItem name=\"待办事项1\"/\u003e,\n        document.getElementById('example')\n    );\n```\n####children属性\n组件属性中有一个特殊的属性`children`，表示子组件，以上面的组件为例，换一种方式定义name：\u003cbr/\u003e\n```JavaScript\n    var TodoItem=React.createClass({\n        render:function(){\n            var props=this.props;\n            return \u003cdiv className=\"todo-item\"\u003e\n                \u003cspan className=\"todp-item__name\"\u003e{props.children}\u003c/span\u003e\n            \u003c/div\u003e\n        }\n    });\n    ReactDOM.render(\n        \u003cTodoItem\u003e待办事项1\u003c/TodoItem\u003e,          //这里组件内的'待办事项1'就是一个子组件，子组件可以是任意元素，文本或标签都可以\n        document.getElementById('example')\n    );\n```\n\n\u003echildren只能为一个元素\n\n####属性类型检查\n为了保证组件属性传递的正确性，可以通过定义propsType对象来约定属性的类型\u003cbr/\u003e\n```JavaScript\nvar MyComponent = React.createClass({\n    propTypes: {\n        optionalArray: React.PropTypes.array,\n        optionalBool: React.PropTypes.bool,\n        optionalFunc: React.PropTypes.func,\n        optionalNumber: React.PropTypes.number,\n        optionalObject: React.PropTypes.object,\n        optionalString: React.PropTypes.string,\n        // 任何可以被渲染的包括，数字，字符串，组件，或者数组\n        optionalNode: React.PropTypes.node,\n        // React 元素\n        optionalElement: React.PropTypes.element,\n        // 枚举\n        optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),\n        // 任意一种类型\n        optionalUnion: React.PropTypes.oneOfType([\n          React.PropTypes.string,\n          React.PropTypes.number,\n          React.PropTypes.instanceOf(Message)\n        ]),\n        // 具体类型的数组\n        optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),\n        // 具体类型的对象\n        optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),\n        // 符合定义的对象\n        optionalObjectWithShape: React.PropTypes.shape({\n          color: React.PropTypes.string,\n          fontSize: React.PropTypes.number\n        }),\n        requiredFunc: React.PropTypes.func.isRequired,\n        requiredAny: React.PropTypes.any.isRequired,\n        // 自定义校验\n        customProp: function(props, propName, componentName) {}\n    }\n});\n```\n\n####属性的单向性传递\nReact是单向数据流模式，数据的流通管道就是props，流动的层级是组件的层级`自顶向下`的方向\u003cbr/\u003e\n一个组件是不能修改自身属性的，组件的属性一定是通过父级传递进来！\u003cbr/\u003e\n####无状态组件属性\n无状态组件，可以添加.propsTypes和.defaultProps属性到函数上\n\n###组件的嵌套组合\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faaaaash%2Flearn-react","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faaaaash%2Flearn-react","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faaaaash%2Flearn-react/lists"}