- A+
所属分类:Web前端
React 全家桶-React基础
用于构建用户界面的JavaScript库。
facebook开源、组件化、声明式编码、React Native移动端开发、虚拟DOM+Diffing算法
官网:https://react.docschina.org/
第一章:React的基本使用
1.相关js库
- react.js:React核心库
- React-dom.js:提供操作DOM的react扩展库
- Babel.min.js:解析JSX语法代码转为JS代码的库
- ES6转ES5
2.创建虚拟DOM的两种方式
- JSX
- JS
3.JSX
React定义的一种类似于XML的JS扩展语法:JS + XML
它最终产生的结果不是字符串,也不是HTML/XML标签,而是一个JS对象
语法规则:
-
标签中混入JS表达式要用{}
-
表达式:一个表达式会返回一个值,而代码块不一定有值返回
-
-
样式的类名指定不要用class属性名,用className
-
内联样式,要用style={{key: value}}的形式去写
-
只能有一个根标签
-
标签必须闭合
-
JSX标签转换规则
- 若小写字母开头,则将该标签转换为html中同名元素,若html中无该标签对应的同名元素,则报错
- 若大写开头,则渲染对应的组件,若组件未曾定义,则报错
4.模块化与组件化
模块:向外提供特定功能的js程序,一般是一个js文件
组件:实现局部功能效果的代码和资源的集合
第二章:React面向组件编程
1.基本理解和使用
1.1 React开发者工具
React Developer Tools 浏览器插件
1.2 效果
函数式组件
<body> <div id="ctx"></div> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <script type="text/babel"> // 1. 创建函数式组件 function Demo () { console.log(this) // 此处的this是undefined,因为babel编译后开启了严格模式 return <h2>用函数定义的组件</h2> } // 2. 渲染组件到页面 ReactDOM.render(<Demo/>, document.getElementById('ctx')) /* 渲染步骤: 1. React解析组件标签,找到了了Demo组件 2. 发现组件是使用函数定义的。随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面上 */ </script> </body>
类式组件
<body> <div id="ctx"></div> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <script type="text/babel"> // 1. 创建类式组件 class MyComponent extends React.Component { render () { console.log(this) return <h2>用类定义的组件,适用于复杂组件的定义</h2> } } ReactDOM.render(<MyComponent/>, document.getElementById('ctx')) /* 渲染步骤: 1. React解析组件标签,找到了了 MyComponent 组件 2. 发现组件是使用类定义的。随后new出该类的实例,并通过该实例调用原型上的render方法,将返回的虚拟DOM转为真实DOM,随后呈现在页面上 */ </script> </body>
2.组件三大核心属性
2.1 state
<body> <div id="ctx"></div> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <script type="text/babel"> class Weather extends React.Component { state = { isHot: false } render () { const {isHot} = this.state return <h2 onClick={this.changeWeather}>天气:{isHot ? '热' : '凉' },风速:{isHot ? '一级' : '二级' }</h2> } // 自定义方法,要用赋值语句+箭头函数(箭头函数没有自己的this) changeWeather = () => { this.state.isHot = !this.state.isHot this.setState(this.state) } } ReactDOM.render(<Weather/>, document.getElementById('ctx')) </script> </body>
2.2 props
类式组件使用props
<body> <div id="ctx"></div> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签进行限制 --> <script src="../js/prop-types.js" type="text/javascript"></script> <script type="text/babel"> class Person extends React.Component { // 构造器是否接收props,是否传递给super?问题取决于:是否希望在构造器中通过this访问props constructor(props) { super(props) console.log('c', this.props) } // 对标签属性进行类型、必要性的限制 static propTypes = { name: PropTypes.string.isRequired } // 指定默认值 static defaultProps = { sex: '未知' } render () { const {name, age, sex} = this.props return ( <ul> <li>姓名:{name}</li> <li>性别:{sex}</li> <li>年龄:{age}</li> </ul> ) } } const p = {name: '逾期', age: 18, sex: '女'} ReactDOM.render(<Person {...p}/>, document.getElementById('ctx')) </script> </body>
函数式组件使用props
<body> <div id="ctx"></div> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签进行限制 --> <script src="../js/prop-types.js" type="text/javascript"></script> <script type="text/babel"> function Person (props) { const {name, sex, age} = props return ( <ul> <li>姓名:{name}</li> <li>性别:{sex}</li> <li>年龄:{age}</li> </ul> ) } // 对标签属性进行类型、必要性的限制 Person.propTypes = { name: PropTypes.string.isRequired } // 指定默认值 Person.defaultProps = { sex: '未知' } const p = {name: '逾期', age: 18, sex: '女'} ReactDOM.render(<Person {...p}/>, document.getElementById('ctx')) </script> </body>
2.3 refs与事件处理
组件内的标签可以定义ref属性来标识自己
2.3.1 字符串形式的refs
<body> <div id="ctx"></div> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签进行限制 --> <script src="../js/prop-types.js" type="text/javascript"></script> <script type="text/babel"> class Demo extends React.Component { showData = () => { const {input1} = this.refs alert(input1.value) } showData2 = () => { const {input2} = this.refs alert(input2.value) } render() { return ( <div> <input ref="input1" type="text" placeholder="点击按钮提示数据"/> <button onClick={this.showData}>点我提示左侧数据</button> <input ref="input2" onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/> </div> ) } } ReactDOM.render(<Demo/>, document.getElementById('ctx')) </script> </body>
2.3.2 回调函数形式的refs
<body> <div id="ctx"></div> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签进行限制 --> <script src="../js/prop-types.js" type="text/javascript"></script> <script type="text/babel"> class Demo extends React.Component { showData = () => { const {input1} = this alert(input1.value) } showData2 = () => { const {input2} = this alert(input2.value) } render() { return ( <div> <input ref={c => this.input1 = c} type="text" placeholder="点击按钮提示数据"/> <button onClick={this.showData}>点我提示左侧数据</button> <input onBlur={this.showData2} ref={c => this.input2 = c} type="text" placeholder="失去焦点提示数据"/> </div> ) } } ReactDOM.render(<Demo/>, document.getElementById('ctx')) </script> </body>
2.3.3 createRef
<body> <div id="ctx"></div> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签进行限制 --> <script src="../js/prop-types.js" type="text/javascript"></script> <script type="text/babel"> class Demo extends React.Component { myRef = React.createRef() showData = () => { console.log(this.myRef) alert(this.myRef.current.value) } render() { return ( <div> <input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/> <button onClick={this.showData}>点我提示左侧数据</button> </div> ) } } ReactDOM.render(<Demo/>, document.getElementById('ctx')) </script> </body>
2.3.4 事件处理
2.4 收集表单数据
2.4.1 受控组件
<body> <div id="ctx"></div> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签进行限制 --> <script src="../js/prop-types.js" type="text/javascript"></script> <script type="text/babel"> class Demo extends React.Component { state = { username: '', password: '' } saveUsername = (e) => { this.setState({username: e.target.value}) } savePassword = (e) => { this.setState({password: e.target.value}) } handleSubmit = (e) => { e.preventDefault() // 阻止form表单提交事件 const {username, password} = this.state alert(`username: ${username.value}, password: ${password.value}`) } render() { return ( <form onSubmit={this.handleSubmit}> 用户名:<input onChange={this.saveUsername} type="text" name="username"/> 密 码:<input onChange={this.savePassword} type="text" placeholder="password"/> <button>login</button> </form> ) } } ReactDOM.render(<Demo/>, document.getElementById('ctx')) </script> </body>
2.4.2 非受控组件
<body> <div id="ctx"></div> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签进行限制 --> <script src="../js/prop-types.js" type="text/javascript"></script> <script type="text/babel"> class Demo extends React.Component { handleSubmit = (e) => { e.preventDefault() // 阻止form表单提交事件 const {username, password} = this alert(`username: ${username.value}, password: ${password.value}`) } render() { return ( <form onSubmit={this.handleSubmit}> 用户名:<input ref={c => this.username = c} type="text" name="username"/> 密 码:<input ref={c => this.password = c} type="text" placeholder="password"/> <button>login</button> </form> ) } } ReactDOM.render(<Demo/>, document.getElementById('ctx')) </script> </body>
2.4.3 函数的柯里化
<body> <div id="ctx"></div> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签进行限制 --> <script src="../js/prop-types.js" type="text/javascript"></script> <script type="text/babel"> class Demo extends React.Component { state = { username: '', password: '' } /** * 高阶函数:如果一个函数符合下面两个规范中的任一,那该函数就是高阶函数 * 1. 若A函数接收的参数是一个函数,那么A就可以称之为高阶函数 * 2. 若A函数调用的返回值依然是一个函数,那么A就可以称之为高阶函数 * 函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数,最后统一处理的函数编码形式 */ saveFormData = (dataType) => { return (e) => { return this.setState({[dataType]: e.target.value}) } } handleSubmit = (e) => { e.preventDefault() // 阻止form表单提交事件 const {username, password} = this.state alert(`username: ${username.value}, password: ${password.value}`) } render() { return ( <form onSubmit={this.handleSubmit}> 用户名:<input onChange={this.saveFormData('username')} type="text" name="username"/> 密 码:<input onChange={this.saveFormData('password')} type="text" placeholder="password"/> <button>login</button> </form> ) } } ReactDOM.render(<Demo/>, document.getElementById('ctx')) </script> </body>
2.5 组件生命周期
2.5.1 旧版生命周期
<body> <div id="ctx"></div> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签进行限制 --> <script src="../js/prop-types.js" type="text/javascript"></script> <script type="text/babel"> class Count extends React.Component { constructor(props) { console.log('Count-constructor') super(props) this.state = { count: 0 } } add = () => { const {count} = this.state this.setState({ count: count+1 }) } death = () => { ReactDOM.unmountComponentAtNode(document.getElementById('ctx')) } force = () => { this.forceUpdate() } componentWillMount() { console.log('Count-componentWillMount') } componentDidMount() { console.log('Count-componentDidMount') } shouldComponentUpdate() { console.log('Count-shouldComponentUpdate') return false } componentWillUpdate() { console.log('Count-componentWillUpdate') } componentDidUpdate() { console.log('Count-componentDidUpdate') } componentWillUnmount() { console.log('Count-componentWillUnmount') } render() { console.log('Count-render') const {count} = this.state return ( <div> <h2>当前求和为: {count}</h2> <button onClick={this.add}>点我+1</button> <button onClick={this.death}>卸载组件</button> <button onClick={this.force}>强制更新</button> </div> ) } } // 父组件A class A extends React.Component { state = { carName: '奔驰' } changeCar = () => { this.setState({carName: '奥迪'}) } render() { return ( <div> <div>A component</div> <button onClick={this.changeCar}>换车</button> <B carName={this.state.carName}/> </div> ) } } // 子组件B class B extends React.Component { // 第一次渲染不会调用这个钩子 componentWillReceiveProps(props) { console.log('B-componentWillReceiveProps', props) } render() { return ( <div> <div>B component: carName={this.props.carName}</div> </div> ) } } // ReactDOM.render(<Count/>, document.getElementById('ctx')) ReactDOM.render(<A/>, document.getElementById('ctx')) </script> </body>
2.5.2 新版生命周期
<body> <div id="ctx"></div> <script src="../newjs/react.development.js"></script> <script src="../newjs/react-dom.development.js"></script> <script src="../js/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签进行限制 --> <script src="../js/prop-types.js" type="text/javascript"></script> <script type="text/babel"> class Count extends React.Component { constructor(props) { console.log('Count-constructor') super(props) this.state = { count: 0 } } add = () => { const {count} = this.state this.setState({ count: count+1 }) } death = () => { ReactDOM.unmountComponentAtNode(document.getElementById('ctx')) } force = () => { this.forceUpdate() } // 在更新之前获取快照,方法返回值将会作为参数传递给componentDidUpdate钩子 getSnapshotBeforeUpdate () { console.log('getSnapshotBeforeUpdate') return 'liergou' } // getDerivedStateFromProps方法的返回值会作为state的值 static getDerivedStateFromProps (props, state) { console.log('getDeriverdStateFromProps', props, state) return null } componentDidMount() { console.log('Count-componentDidMount') } shouldComponentUpdate() { console.log('Count-shouldComponentUpdate') return true } componentDidUpdate(preProps, preState, snapshotValue) { console.log('Count-componentDidUpdate', preProps, preState, snapshotValue) } componentWillUnmount() { console.log('Count-componentWillUnmount') } render() { console.log('Count-render') const {count} = this.state return ( <div> <h2>当前求和为: {count}</h2> <button onClick={this.add}>点我+1</button> <button onClick={this.death}>卸载组件</button> <button onClick={this.force}>强制更新</button> </div> ) } } ReactDOM.render(<Count age={88}/>, document.getElementById('ctx')) </script> </body>