一 . 基础概念
- JSX是一种JavaScript的语法扩展,拓展了 XML 写法。
- 在 React 中,所有的东西看做是 JS,HTML 结构是 JS,CSS 样式描述也是 JS。
- React 允许直接在 JS 文件中写 HTML 代码
- 因为 JSX 允许直接直接在 JS 中写 XML 语法,所以特别灵活
二 . react中的数据显示
-
字符串直接显示
-
数字直接显示
-
对象, 不能直接显示会报错
-
布尔值 不会显示
-
数组, 数组里是字符串或数字就会把每一项都显示出来, 对象会报错
-
数据绑定用{} vue里用{{}}
-
列表渲染
使用数组的 map 方法把数组映射成 JSX 数组。import React from 'react'; const foods = [ { id:1, name:'牛排', price: 99 }, { id:2, name:'鸡排', price: 199 }, { id:3, name:'鸭排', price: 199 }, ]; function App() { return ( <div className="App"> <ul> { foods.map((v,i)=><li key={i}>食物名称:{v.name},价格是:{v.price}</li>) } </ul> </div> ); } export default App;
-
条件渲染
{ true ? <h1>结构1</h1> : <h2>结构2</h2> }
-
短路运算
{ true && <h1>结构1</h1> }
-
属性绑定用{},
<img src={变量} />
-
行内样式绑定
import React from 'react'; const styleObj = { width:'200px', height:'200px', backgroundColor:'pink', }; function App() { return ( <div className="App"> <div style={styleObj}>盒子</div> </div> ); } export default App;
要把样式放到对象里
-
渲染html字符串
import React from 'react'; const htmlStr = '<h1>标题字符串</h1>'; function App() { return ( <div className="App"> <div dangerouslySetInnerHTML={{__html: htmlStr}}></div> </div> ); } export default App;
用dangerouslyInnerHTML={{__html: ‘html字符串’}}来显示
-
组件多个属性可以用结构语法
import React from 'react'; const props = { type: "text", 'data-tip': '请输入内容', className:"box" } function App() { return ( <div className="App"> <input {...props} /> </div> ); } export default App;
三 . 组件
-
函数组件
- 外观就是一个函数
- this 指向 undefined
- 没有内部的数据 state - 状态,函数式组件的数据一般是父组件传递过来的。
- 没有组件生命周期
- 运行速度和体验比较好
- 适合比较简单业务的功能
function Btn(props){ return <div>按钮组件</div> }
- 函数组件首字母必须大写
- 通过参数获取父组件传递的属性或方法
-
类组件
- 外观就是一个 es6 的 class
- 有 this 指向
- 有内部自己的数据 state - 状态
- 修改 state
this.setState
更新数据和视图。 - 有组件的生命周期函数
- 适合做复杂业务功能
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; class Home extends Component { state = { msg: "大家好呀" } handleClick() { // undefined console.log(this); } render() { return ( <div> <div onClick={this.handleClick} >小标题</div> </div> ) } } ReactDOM.render(<Home />, document.getElementById('root'))
- 使用箭头函数就可以避免事件内部this为undefined为空的问题, 也可以使用bind来处理
<div onClick={this.handleClick.bind(this)} >小标题</div>
-
受控组件
必须同时给与onChange
事件和绑定value
属性。
value 值如果绑定了数据,默认情况 value 是只读的。
需要通过 onChange 绑定事件获取表单值和改变表单值。
更多受控组件
<input type="text" />
<input type="checkbox" />
<input type="radio" />
<textarea />
<select />
四 . 组件父子传值
- 父传子通过属性传值
子组件通过props 获取class HomeTop extends Component { render() { return ( <h1>屋顶的颜色是 {this.props.acolor} 尺寸 {this.props.asize}</h1> ) } } class Home extends Component { state = { color: "blue", size: 100 } render() { return ( <div> <HomeTop acolor={this.state.color} asize={this.state.size} ></HomeTop> </div> ) } }
- 子传父通过事件触发的方式
父组件先把函数传给子组件, 子组件要触发时九调用父组件传递的事件, 并通过参数向父组件传递函数import React from 'react'; function Btn1(props) { const obj = { color: 'red' }; const fn = () => { props.aa(obj); }; return <button onClick={fn}>按钮1-变红</button>; } function Btn2(props) { const obj = { color: 'blue' }; const fn = () => { props.bb(obj); }; return <button onClick={fn}>按钮2-变蓝</button>; } class App extends React.Component { state = { color: 'green' }; changeColor = (obj) => { this.setState({ color: obj.color }); }; render() { return <div> <Btn1 aa={this.changeColor} ></Btn1> <Btn2 bb={this.changeColor}></Btn2> <div style={{ backgroundColor: this.state.color }}>父组件的某个盒子</div> </div>; } } export default App;
五 . 生命周期
- 组件挂载
componentWillMount 组件挂载前的钩子函数
componentDidMount 组件挂载后的钩子函数 - 组件数据更新
shouldComponentUpdate 在更新更新组件前的拦截器
componentDidMount 组件数据更新后的钩子函数
等等其他钩子函数 - 组件卸载
componentWillUnmount 组件卸载前的钩子函数
六 . 组件性能问题
- 高性能组件
就是在父组件更新时, 会触发子组件的更新, 高性能组件就是通过判断判断组件的props和state, 当它们没有发生变化时就不更新,可以通过继承React.PureComponent和数据深拷贝来实现
class List extends React.PureComponent {
render() {
return (
<ol>
{
this.props.list.map((item, index) => <li onDoubleClick={() => this.props.aa(index)} key={item}>{item}</li>)
}
</ol>
);
}
}
React.PureComponent, 也是在shouldComponentUpdate进行了props和state的比较, 不进行数据深拷贝的话有props里的数组对象始终指向同一个对象怎么比较都相等
通过JSON.parse(JSON.stringify( xxx ))来进行深拷贝
六 . 样式
-
全局样式
直接import 导入import './App.css'; import './style/aaa.css';
-
局部样式
局部样式命名有规范:***.module.css
这是脚手架工具规定的。
导入的时候保存变量:import 变量名 from '***.module.css'
;
把原本的类名变成对象属性的写法:className={styles.btn}
import style from "./style.module.scss"; <button className={style.btn}>嘎嘎嘎嘎嘎</button>
七 . redux
-
Redux 的设计思想
视图与状态是一一对应的。
所有的状态,保存在一个对象里面。 -
引入创建仓库的方法
import { createStore } from 'redux';
-
创建管理员
const defaultState = { aa: 123 }; const reducer = (state = defaultState) => { return state; };
-
创建仓库对象
const store = createStore(reducer);
-
获取仓库数据
store.getState()
-
修改仓库状态
store.dispatch(action)
管理员函数会被触发, 要在管理员函数里操作仓库数据
store.dispatch只是发送action数据 -
设置监听函数, 一旦仓库数据发生变化九自动执行这个函数
const listener = ()=> {} let unsubscribe = store.subscribe(listener);
unsubscribe 是subscribe返回的取消订阅的函数
let unsubscribe()会取消监听state数据变化
八 . react-redux
-
react-redux 是基于 原生 redux 上封装的一个插件库,用起来比原生 redux 简单一些
-
创建管理员
-
创建仓库和redux一样
-
在整个项目的入口引入仓库, 引入Provider
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import { Provider } from 'react-redux'; import store from './store'; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') );
用Provider组件包括根组件, 并把仓库实例传递过去
-
用connect 来处理组件, 把仓库里的值映射到props里
import React from 'react'; import { connect } from 'react-redux'; class Header extends React.Component { render() { return ( <header> <h1>页面头部访问 store 数据: {this.props.num}</h1> </header> ); } } const mapStateToProps = (state) => ({ num: state.num }); const superHeader = connect(mapStateToProps)(Header); export default superHeader;
connect有两个参数mapStateToProp用来将仓库的数据映射到props里
mapDispatchToProps 是将dispatch方法映射到props里import React from 'react'; import { connect } from 'react-redux'; class Main extends React.Component { render() { return ( <section> <hr /> <h3>页面主体{this.props.num}</h3> <button onClick={this.props.aaaa}>改仓库状态</button> <hr /> </section> ); } } const mapStateToProps = (state) => ({ num: state.num }); const mapDispatchToProps = (dispatch) => ({ aaaa() { const action = { type: 'add', value: 1 }; dispatch(action); } }); const SuperMain = connect(mapStateToProps, mapDispatchToProps)(Main); export default SuperMain;
九 . 在配置嵌套路由时, 嵌套路由的父路由千万不要带exact不然子路由会匹配不到!!!