React系统学习:从基础语法到虚拟DOM
📝 本文基于作者学习笔记,系统整理了 React 基础知识,适合前端开发者入门参考。
react是facebook开源的,为什么高效的原因,是因为使用了虚拟dom技术,可以很大程度的复用。
1.基本语法
helloWorld,babel的引入是为了将jsx转换为js,使用jsx可以更快的创建虚拟dom。
<!DOCTYPE html><html lang="en">
<head> <meta charset="UTF-8"> <title>hello_react</title></head>
<body> <div id="test"></div> <!-- 先引入核心库、扩展库、babel库 --> <script type="text/javascript" src="../js/react.development.js"></script> <script type="text/javascript" src="../js/react-dom.development.js"></script> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/babel"> const VDOM = <h1>hello,React</h1> ReactDOM.render(VDOM,document.getElementById('test')) /*此处不写引号,不是字符串*/ </script></body>
</html>JSX的基本语法:
- 定义虚拟DOM时,不要写引号
- 标签中混入JS表达式要用{},注意用const xxx=可以接收的才叫表达式
- 样式的类名指定不要用class,要用className
- 内联样式,要用style={{key
}}形式 - 只有一个根标签
- 标签必须闭合
- 标签首字母: (1)若小写字母开头,则把标签转化为html同名元素,若没有对应同名元素则报错 (2)若大写字母开头,react就去渲染对应的组件,若组件没有定义则报错。
<!DOCTYPE html><html lang="en">
<head> <meta charset="UTF-8"> <title>hello_react</title></head><style> .title { font-size: large; color: blue; }</style>
<body> <div id="test"></div> <!-- 先引入核心库、扩展库、babel库 --> <script type="text/javascript" src="../js/react.development.js"></script> <script type="text/javascript" src="../js/react-dom.development.js"></script> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/babel"> const title = 'title' const VDOM = ( <div> <h1 className={title} style={{ color: 'red' }}> <span>hello,React</span> </h1> <Good></Good> </div>
) ReactDOM.render(VDOM, document.getElementById('test')) /*此处不写引号,不是字符串*/ </script></body>
</html>2.面向组件编程
js的模块化只是拆分html,而组件编程则是html、css、js、img、video等整合起来是一个组件,优点是复用编码,提高效率。
2.1函数式组件
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>hello_react</title> </head> <style> .title { font-size: large; color: blue; } </style>
<body> <div id="test"></div> <!-- 先引入核心库、扩展库、babel库 --> <script type="text/javascript" src="../js/react.development.js"></script> <script type="text/javascript" src="../js/react-dom.development.js" ></script> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/babel"> function Demo() { return <h1>我是一个函数式组件(适用于简单的自定义)</h1>; } ReactDOM.render(<Demo />, document.getElementById("test")); </script> </body></html>2.2类式组件
2.2.1类的初识
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>hello_react</title> </head> <style> .title { font-size: large; color: blue; } </style>
<body> <div id="test"></div> <!-- 先引入核心库、扩展库、babel库 --> <script type="text/javascript" src="../js/react.development.js"></script> <script type="text/javascript" src="../js/react-dom.development.js" ></script> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/babel"> // 创建一个Person类 class Perseon { // 构造器方法 constructor(name, age) { this.name = name; this.age = age; } // 一般方法 speak() { // speak方法在类的原型对象上,供实例使用 // 通过Person实例调用speak时,speak中的this就是Person实例 console.log(`我叫${this.name},我已经${this.age}了`); } }
class Student extends Perseon { constructor(name, age, grade) { // 子类使用构造器一定要使用super且必须在前面 super(name, age); this.grade = grade; } // 重写父类继承的方法 speak(name,age,grade){ console.log(`我叫${this.name},我已经${this.age}了,在读${this.grade}`); } } const mm = new Perseon("小满", 10); console.log(mm); mm.speak(); // call可以更改函数里的this指向 mm.speak.call({ name: "didi", age: 8 });
const ls = new Student("李四", "18", "大一"); ls.speak(); </script> </body></html>2.2.2使用
React解析组件标签时,发现组件是使用类定义的,会new出该类实例,并通过该实例调用到原型上的render
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>hello_react</title> </head> <style> .title { font-size: large; color: blue; } </style>
<body> <div id="test"></div> <!-- 先引入核心库、扩展库、babel库 --> <script type="text/javascript" src="../js/react.development.js"></script> <script type="text/javascript" src="../js/react-dom.development.js" ></script> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/babel"> class MyComponent extends React.Component{ render(){ return '我是一个类式组件' } }
ReactDOM.render(<MyComponent/>,document.getElementById('test')) </script> </body></html>3.State状态
借助构造器初始化状态并使用,通过点击事件修改状态。
3.1标准写法(强制绑定)
下面是标准写法,借助构造器的this对state进行初始化
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>hello_react</title> </head> <style> .title { font-size: large; color: blue; } </style>
<body> <div id="test"></div> <!-- 先引入核心库、扩展库、babel库 --> <script type="text/javascript" src="../js/react.development.js"></script> <script type="text/javascript" src="../js/react-dom.development.js" ></script> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/babel"> class Weather extends React.Component { constructor(props) { super(props); // 初始化状态 this.state = { isHot: true, wind: "微风" }; // 解决changeWeather中指向问题 this.changeWeather = this.changeWeather.bind(this); } render() { const { isHot, wind } = this.state; return ( <h1 onClick={this.changeWeather}> 今天天气{isHot ? "炎热" : "凉爽"},{wind} </h1> ); }
changeWeather() { const isHot = this.state.isHot; this.setState({ isHot: !isHot }); console.log("修改天气:", this.state.isHot); } }
ReactDOM.render(<Weather />, document.getElementById("test")); </script> </body></html>

3.2简化写法(箭头函数)
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>hello_react</title> </head> <style> .title { font-size: large; color: blue; } </style>
<body> <div id="test"></div> <!-- 先引入核心库、扩展库、babel库 --> <script type="text/javascript" src="../js/react.development.js"></script> <script type="text/javascript" src="../js/react-dom.development.js" ></script> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/babel"> class Weather extends React.Component { // 自定义状态 state = { isHot: true, wind: "微风" }; render() { const { isHot, wind } = this.state; return ( <h1 onClick={this.changeWeather}> 今天天气{isHot ? "炎热" : "凉爽"},{wind} </h1> ); }
// 自定义方法——用赋值语句+箭头函数的形式 changeWeather = () => { console.log(this); const isHot = this.state.isHot; this.setState({ isHot: !isHot }); console.log("修改天气:", this.state.isHot); }; }
ReactDOM.render(<Weather />, document.getElementById("test")); </script> </body></html>4.props多种属性
三点运算符…表示展开,是对于一个数组。
4.1基本使用
{...Person}在原生es6语法中,表示克隆一个对象{...Person,name:'jack'}表示克隆一个对象并替换<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>hello_react</title> </head> <body> <div id="test1"></div> <div id="test2"></div> <div id="test3"></div> <!-- 先引入核心库、扩展库、babel库 --> <script type="text/javascript" src="../js/react.development.js"></script> <script type="text/javascript" src="../js/react-dom.development.js" ></script> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/babel"> class Weather extends React.Component { render() { const { area, day, weather } = this.props; return ( <ul> <li>{area}</li> <li>{day}</li> <li>{weather}</li> </ul> ); } }
const p = { area: "福州", day: "11月25日", weather: "晴" }; //这里不是表示克隆而是展开p,因为react+babel,原生会报错,而且只有标签属性可以 ReactDOM.render(<Weather {...p} />, document.getElementById("test1"));
ReactDOM.render( <Weather area="泉州" day="11月25日" weather="阴" />, document.getElementById("test2") );
ReactDOM.render( <Weather area="厦门" day="11月25日" weather="大风" />, document.getElementById("test3") ); </script> </body></html>4.2标签属性限制
Person.propTypes = { name: PropTypes.string.isRequired,//限制name必传,且为字符串 sex: PropTypes.string,//限制sex为字符串 age: PropTypes.number,//限制age为数值 speak:PropTypes.func//限制speak为函数 };
Person.defaultProps = { sex: "保密",//sex默认值保密 };4.3简写
class Person extends React.Component { static propTypes = { name: PropTypes.string.isRequired, //限制name必传,且为字符串 sex: PropTypes.string, //限制sex为字符串 age: PropTypes.number, //限制age为数值 speak: PropTypes.func, //限制speak为函数 };
static defaultProps = { sex: "保密", //sex默认值保密 }; render() { const { name, sex, age } = this.props; return ( <ul> <li>{name}</li> <li>{sex}</li> <li>{age + 1}</li> </ul> ); } }5.refs
在 React 中,refs 是用来访问和操作 DOM 元素或组件实例的一种方式。通过 refs,开发者可以直接与 DOM 进行交互,而无需依赖 React 的状态管理和生命周期方法。
5.1字符串形式
class Demo extends React.Component { showData = () => { console.log(this); const {input1} = this.refs console.log(input1.value); }; render() { return ( <div> <input ref="input1" type="text" placeholder="点击按钮提示数据" /> <button onClick={this.showData}>获取数据</button> <input id="input2" placeholder="失去焦点提示数据" /> </div> ); } }
ReactDOM.render(<Demo />, document.getElementById("test1"));5.2回调函数形式
<script type="text/babel"> class Demo extends React.Component { showData = () => { const { input1 } = this.refs; console.log(this.input1.value); }; render() { return ( <div> <input ref={(c) => (this.input1 = c)} type="text" placeholder="点击按钮提示数据" /> <button onClick={this.showData}>获取数据</button> </div> ); } } ReactDOM.render(<Demo />, document.getElementById("test1"));</script>5.3createRef形式
myRef1 = React.createRef();
<input ref={this.myRef1} type="text" placeholder="点击按钮提示数据"/><script type="text/babel"> class Demo extends React.Component { state = { isHot: true }; myRef1 = React.createRef(); myRef2 = React.createRef();
showData = () => { console.log(this.myRef1.current.value); };
showData2 = () => { alert(this.myRef2.current.value); };
changeWeather = () => { const { isHot } = this.state; this.setState({ isHot: !isHot }); }; render() { const { isHot } = this.state;
return ( <div> <h1>今天天气很{isHot ? "炎热" : "凉爽"}</h1> <input ref={this.myRef1} type="text" placeholder="点击按钮提示数据" /> <button onClick={this.showData}>获取数据</button> <button onClick={this.changeWeather}>点击切换天气</button> <input onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="失去焦点提示数据" /> </div> ); } } ReactDOM.render(<Demo />, document.getElementById("test1")); </script>6.react中的事件处理
不要过度使用ref,如果发生事件的元素就是你要操作的元素的时候就可以不适用ref。
//使用ref的版本showData2 = () => { alert(this.myRef2.current.value);};
<input nBlur={this.showData2} ref={this.myRef2} type="text" placeholder="失去焦点提示数据"/>
//不使用ref的版本showData2 = (event) => { alert(event.target.value);};
<input nBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>7.react中收集表单数据
优先使用受控组件,因为使用非受控组件需要使用ref
7.1非受控组件
现用现取属于非受控
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>hello_react</title> </head> <body> <div id="test1"></div> <div id="test2"></div> <div id="test3"></div> <!-- 先引入核心库、扩展库、babel库 --> <script type="text/javascript" src="../js/react.development.js"></script> <script type="text/javascript" src="../js/react-dom.development.js" ></script> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/javascript" src="../js/prop-types.js"></script> <script type="text/babel"> class Login extends React.Component { handleSubmit = (event) => { event.preventDefault(); const { username, password } = this; alert(`你输入的用户名是${username.value},密码是${password.value}`); }; render() { return ( <form action="http://www.baidu.com" onSubmit={this.handleSubmit}> 用户名: <input type="text" ref={(c) => (this.username = c)} name="username" /> 密码: <input type="password" ref={(c) => (this.password = c)} name="password" /> <button>登陆</button> </form> ); } } ReactDOM.render(<Login />, document.getElementById("test1")); </script> </body></html>7.2受控组件
页面中所有输入类的dom,随着输入可以维护到状态中,需要使用的时候通过状态中读取。
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>hello_react</title> </head> <body> <div id="test1"></div> <div id="test2"></div> <div id="test3"></div> <!-- 先引入核心库、扩展库、babel库 --> <script type="text/javascript" src="../js/react.development.js"></script> <script type="text/javascript" src="../js/react-dom.development.js" ></script> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/javascript" src="../js/prop-types.js"></script> <script type="text/babel"> class Login extends React.Component { // 初始化状态 state = { username: "", //用户名 password: "", //密码 }; handleSubmit = (event) => { event.preventDefault(); //阻止表单提交 const { username, password } = this.state; alert(`你输入的用户名是${username},密码是${password}`); };
saveUsername = (event) => { this.setState({ username: event.target.value }); };
savePassword = (event) => { this.setState({ password: event.target.value }); };
render() { return ( <form onSubmit={this.handleSubmit}> 用户名: <input type="text" name="username" onChange={this.saveUsername} /> 密码: <input type="password" name="password" onChange={this.savePassword} /> <button>登陆</button> </form> ); } } ReactDOM.render(<Login />, document.getElementById("test1")); </script> </body></html>*8.生命周期
下面是一副生命周期的流程,挂载比较简单就是一直往下走;setState就是先往左再往下;forceUpdate也是先往左再往下

初始化阶段:由ReactDOM.render()触发---初次渲染
- constructor()
- componentWillMount()
- render()
- componentDidMount() ===> 常用,一般在钩子里做初始化操作,例如:开定时器,发网络请求,订阅消息
更新阶段:由组件内部this.setState()或父组件render触发
- shouldComponentUpdate()
- componentWillUpdate()
- render() ==> 必须使用一个
- componentDidUpdate()
卸载组件:由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount ==>常用,一般做收尾动作,例如:关闭定时器取消订阅
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>生命周期</title> </head> <body> <div id="test"></div> <!-- 先引入核心库、扩展库、babel库 --> <script type="text/javascript" src="../js/react.development.js"></script> <script type="text/javascript" src="../js/react-dom.development.js" ></script> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/javascript" src="../js/prop-types.js"></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("test")); };
force = () => { this.forceUpdate(); }; // 组件将要挂载的钩子 componentWillMount() { console.log("Count---componentWillMount"); }
// 组件挂载完毕的钩子 componentDidMount() { console.log("Count---componentDidMount"); }
// 组件将要卸载的钩子 componentWillUnmount() { console.log("Count---componentWillUnmount"); }
// 控制组件更新的“阀门” shouldComponentUpdate() { console.log("Count---shouldComponentUpdate"); return true; }
// 组件将要更新的钩子 componentWillUpdate() { console.log("Count---componentWillUpdate"); }
// 组件更新完毕的钩子 componentDidUpdate() { console.log("Count---componentDidUpdate"); }
render() { console.log("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> ); } }
class A extends React.Component { state = { carName: "奔驰" }; changeCar = () => { this.setState({ carName: "奥迪" }); }; render() { return ( <div> <div>我是组件A</div> <button onClick={this.changeCar}>换车</button> <B carName={this.state.carName} /> </div> ); } }
class B extends React.Component { componentWillReceiveProps(props) { // 这个函数有坑,非首次更新才执行 console.log("B---componentWillReceiveProps"); } render() { return ( <div> <div>我是B组件,接收到的车是{this.props.carName}</div> </div> ); } } ReactDOM.render(<A />, document.getElementById("test")); </script> </body></html>相关推荐
- Bootstrap Table使用教程:数据表格实战 - 前端组件库
- Bootstrap响应式二级导航菜单:悬停展开实现 - 前端 UI 交互
- Jenkins流水线发布实战:React+SpringBoot全栈部署 - React 项目部署
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!