React概念
React是什么
react是用于构建用户界面的 JavaScript 库,React主要用于构建UI,官方认为 React 是 MVC 中的 V(视图)
仍然是数据驱动,数据变了,视图会同步发生变化,从该角度也可认为为MVVM模式
React的起源
React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源
React开发工具
react-devTools
安装方式:cnpm install -g react-devtools@3.0.0
启动:react-devtools,启动后将script标签代码注入自己的代码中
什么是 jsx
html/xml + js混写的写法我们称之为JSX,然后要在script标签中写jsx的话,我们需要type的值写为text/babel
jsx语法
- 在jsx中写js表达式:表达式需要写在花括号 {} 中
- 在jsx中写样式:
<h1 style={{border:"10px solid red"}}>{this.state.title}</h1>
- 在jsx中写注释:
{/*注释*/}
- 在jsx中写数组
var arr = [
<h1 key="1">hello</h1>,
<h2 key="2">你好</h2>,
];
var arr1 = [
"hello", "你好"
];
ReactDOM.render(
<div>
{arr}
{arr1}
</div>,
document.getElementById('root')
);
- jsx标签中属性写法
//1.如果属性名由多个单词组成,应该使用小驼峰命名法
<input tabIndex="3"/>
//2.如果值是一个变量我们可以包裹在{}里面,常量可以直接包裹在双引号中
<input tabIndex="3" placeholder="hello" title={ele.firstName + ele.sex} />
//3.几个特殊的属性
<label htmlFor ="test">label:</label>
<input className="zs" id="test"/>
- JSX的本质:
jsx默认浏览器是认不到的,需要使用babel转译,然后会被转译为
React.createElement() 函数调用
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);//与下方代码效果相同
const element = React.createElement(
'h1',
{ className: 'greeting' },
'Hello, world!'
);
React中实现类似于VUE的插槽:this.props.children
class A extends React.Component {
render() {
return (
<div style={{ border: "1px solid red" }}>
<h1>hello</h1>
{ this.props.children}
</div>
)
}
}
//渲染与调用组建
ReactDOM.render(
<div>
<A>
<h1>123</h1>
</A>
</div>,
document.getElementById('root')
);
React中的条件渲染和列表渲染的实现
if:与原生类似,返回标签
for:与原生类似
React组件
React组件定义:
function 组件名(props){} //function定义
class 组件名 extends React.Component{
render(){
return ()
}
}//class定义
组件传参:
<HelloMessage name="张三"></HelloMessage>
//在子组件中使用,this.props获取
Props类型验证:
- 下载prop-types.js文件
- 在组件的后面添加验证代码
MyCom2.propTypes = {
myp1: PropTypes.string.isRequired,
}
//设置默认值
MyCom2.defaultProps = {
myp1: '我是默认值。。。。'
};
React中的事件绑定方式
- 在构造函数中进行绑定,这样就能直接获取到组件实例了【推荐】
constructor(props) {
super(props);
this.test=this.test.bind(this);
}
- 在和事件绑定时在进行绑定this【较麻烦,不推荐】
<button onClick={this.test.bind(this)}>update</button>
}
- 通过箭头函数进行调用
<button onClick={()=>{this.test()}}>update</button>
}
修改state的方法
this.setState({key:'value'});//方式一
this.setState(function(state,props){
return{key:'value'
};})
在React组件中获取各数据说明
- 获取props: this.props.属性名
- 获取state:this.state.状态名
- 获取方法:this.方法名
React组件通信
父到子:父组件通过props给子组件传参即可实现通信
子到父: 在react中,父组件通过props 给子组件传递数据,子组件则是通过调用父组件传给它的函数给父组件传递数据。【和vue大致是一样的】
兄弟组件间组件通信: 通过父级组件中转实现通信
任意组件间通信:context
- 在顶层组件中写一个getChildContext方法,返回要给后代组件使用的数据
- 声明getChildContext方法中返回数据的类型
- 在后代组件中声明下需要哪些content数据,并给上类型,然后就可以使用顶层组件中的数据了
React脚手架— creat-react-app
- 创建react项目
npm init react-app 项目名(npm 6+)
npx create-creact-app 项目名 (npm5.2+)
yarn creat-react-app 项目名 (yarn 0.25+) - 运行
cd 项目文件名
npm start
文件结构
PWA(渐进式增强应用)–serviceWorker.js 与 manifest.json
项目中serviceWorker.js 与 manifest.json这两个文件代表的是用于PWA应用的的控制文件
在入口文件中serviceWorker.unregister()代表不启用pwa,修改为serviceWorker.register则会启用pwa
eslint配置
向package.json中注入eslint规则
在脚手架项目中实现任意组件通信(订阅发布者模式,类似于vue中的bus)
1.安装相关模块:events
cnpm i events -S 或 yarn add events -S
2.创建event.js文件
import { EventEmitter } from "events";
export default new EventEmitter();
3.在需要通信的组件中引入event.js文件
4.发消息
button onClick={() => {
emitter.emit("showDetail", {
isShow: true
});
}}>点击事件</button>
5.接收消息
componentDidMount() {
emitter.on("showDetail", data => {
console.log("one组件收到消息如下:",data);//true
});
}
React路由—React-router-dom
React的两种模式
- 引入browserRouter与HashRouter
- 使用browserRouter标签或者HashRouter标签包裹路由
borwserRouter(history模式):url地址栏上不存在#,就是/,但页面无法刷新,刷新会去请求该地址的后端接口。
hashRouter(hash模式):url地址栏上存在#
Switch的使用—只匹配一个路由
当存在同一路径存在多个路由时只匹配一个路由
可以使用Switch并在路由的末尾增加一个path=’*'的路由以作为路由404的返回
路由传参
只有使用component或者使用render的路由才能够实现传参
在子路由中的获取:通过打印this.props会发现 包含history,location,match,
History:表示整个历史记录相关的,可以使用它实现编程式路由 push,replace
Location:相当于URL 的对象形式表示,可以使用它获取查询参数 search
Match:包含了具体的 url 信息,可以使用它获取动态路径参数。params
使用render进行路由组件传参(render={函数})
<BrowserRouter>
<Switch>
{/* render可以直接渲染一个组件,还可以传入参数 */}
<Route path='/' exact render={() => <One op1={this.props.ap1} test={666}></One>} ></Route>
{/* render可以直接渲染一个DOM节点 */}
<Route path='/h1' exact render={() => <h1>222</h1>}></Route>
{/* 可以获取到props参数,也可以做逻辑判断 */}
<Route path='/two' exact render={(props) => {
console.log("props:",props)
if (sessionStorage.state) return <h1>登录成功</h1>
else return <h1>登录失败</h1>
}}></Route>
</Switch>
</BrowserRouter>
React的重定向 —Redirect
- 引入redirect模块 import Redirect from react-router-dom
- 使用redirect模块
<Redirect to=/one" from='/' exact></Redirect>
需要精确匹配
link—路由跳转
import {Link} from react-router-dom
<Link to='/one'></Link>
<Link to={pathname:'/two' search:'?name=zs'}
Link标签应该写在hashRouter与browserRouter之间
Link标签会被解析为a标签
to的值可以为一个对象,pathname:路径,search:查询参数
React传递动态路径参数
<Route path='/three:id' exact component={Three}></Route>
<Link to='/three:zs'><span>去Three组件</span></Link>|
<h3>ID: {this.props.match.params.id}</h3>
在router标签的path后跟:参数名
在lin标签的to后跟:参数值
在子路由中通过this.props.match.params.参数名 接收
React传递查询参数
<Link to='/one?name=zs$sex=nan' ><span>去One组件</span></Link>|
<h2>参数查询为:{this.props.location.search}</h2>
在Link标签后跟?参数名=参数值
多个参数之间以$隔开
在子路由中通过this.props.location.search获取(此时的格式并非常规的对象形式,而是字符串需要自行处理)
this.props.history–编程式路由
在通过 Route 标签渲染的组件中,可以使用this.props.history 实现编程式路由。
<button onClick={this.toOne.bind(this)}><span>去one组件</span></button>
toOne() {
this.props.history.push('/one')
this.props/history.push({pathname:'/one:zs?sex=man',})
}
push方法的参数可以为一个对象
withRouter—可以使路由组件的子路由使用编程式路由
import { withRouter } from 'react-router-dom';
export default withRouter(ToOne)
- 引入withRouter模块
- 在导出组件时使用withRouter包裹
嵌套路由
<Link to="/two/1" ><span>去two1组件</span></Link>
<Link to="/two/2" ><span>去two2组件</span></Link>
<Link to="/two/3" ><span>去two3组件</span></Link>
<Switch>
<Route path="/two/" exact component={Two1}></Route>
<Route path="/two/1" component={Two1}></Route>
<Route path="/two/2" component={Two2}></Route>
<Route path="/two/3" component={Two3}></Route>
</Switch>
在子路由中写入
解析配置对象(类似VUE)
const routes = [
{
path: "/",
component: One
},
{
path: "/one",
component: One
},
{
path: "/two",
component: Two,
children: [
{
path: "/two/",
component: Two1
},
{
path: "/two/1",
component: Two1
}
]
}
];
<Switch>
{routes.map(function (routeobj, i) {
//如果当前路由具有子路由,于是Route上不能加exact属性
if (routeobj.children) {
return <Route key={i} path={routeobj.path} render={function (props) {
return <routeobj.component {...props} routes={routeobj.children}> </routeobj.component>
}}></Route>
}
//如果当前路由不具有子路由,于是Route上可以加exact属性
else {
return <Route exact key={i} path={routeobj.path} render={function (props) {
return <routeobj.component {...props} > </routeobj.component>
}}></Route>
}
})}
</Switch>
react状态管理 ——react-redux
Action ---- 基本等价与vue中的action,代表了用户的行为
Reducer —等价于vue中的mutations,用于修改state,从而改变页面
Store ---- 基本等价于vue中的store.state,存储所有的全局数据
使用:
- react-redux 安装 npm i react-redux redux -S
- import {createStore} from ‘redux’ —redux用于创建Store对象
import {Provider,connect} from ‘react-redux’ 提供方法将redux绑定到react上 - 定义可能的用户行为-action对象
- 定义这些行为的处理方式–reducer函数
- 根据reducer创建store对象,生产state数据
- 定义辅助函数将store中的state映射到组件中
- 用connect方法链接map函数和组件
- 在根组件的外面包裹Provider向辅助函数传入store中的state
- 最后在组件中通过props使用store中的数据
react-redux的规范化流程
- 创建一个store文件夹,放所有redux相关的文件
- 在store目录下,把所有的行为类型集中到一起定义为一个actions_type.js文件
- 在store目录下,在创建一个actions.js文件,放所有的action。
- 在store目录下,创建一个reducers文件夹,每个里面有很多reducer文件,然后把所有的reducer文件合并在一起返回到indexReducer中
- 在入口文件index.js中根据reducer创建Store对象
后面的流程就一样了,包裹容器,传入store等
组成部分
- reducer
- action
- action_type
- createAction 自定义action的函数
- store
- component view
store传递参数
var store = createStore(allReducer,{userName:'zs'})
dispatch传参
- 定义创建action的函数 createAction(actionType,param)
- 在mapDispatchProps函数中使用定义的函数createAction
- 在组件中实际调用时传入
dispatch派发action时实现异步操作
- 定义一个用于请求的json文件test.json
- 在组件中进行fetch请求(在请求成功后,再派发dispatch)